<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>lighty.io Archives - lighty.io</title>
	<atom:link href="https://lighty.io/category/lighty-io/feed/" rel="self" type="application/rss+xml" />
	<link>https://lighty.io/category/lighty-io/</link>
	<description>SDN Made Easy</description>
	<lastBuildDate>Fri, 30 Oct 2020 14:21:45 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.9.1</generator>

<image>
	<url>https://lighty.io/wp-content/uploads/2018/01/cropped-cropped-Asset-1-32x32.png</url>
	<title>lighty.io Archives - lighty.io</title>
	<link>https://lighty.io/category/lighty-io/</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>[RESTCONF API] Topology Interaction</title>
		<link>https://lighty.io/restconf-api-topology-interaction/</link>
		
		<dc:creator><![CDATA[lighty.io]]></dc:creator>
		<pubDate>Thu, 23 Jan 2020 12:58:28 +0000</pubDate>
				<category><![CDATA[lighty.io]]></category>
		<guid isPermaLink="false">https://lighty.io/?p=1324</guid>

					<description><![CDATA[<p>WHAT IS AN API REQUEST? REST API request is an HTTP method. It lets you send a request from an endpoint to your server (controller). You can use it if you want to retrieve some information from the server or connected device, or if you want to do some changes<a class="moretag" href="https://lighty.io/restconf-api-topology-interaction/"> Read more</a></p>
<p>The post <a href="https://lighty.io/restconf-api-topology-interaction/">[RESTCONF API] Topology Interaction</a> appeared first on <a href="https://lighty.io">lighty.io</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<h4 class="wp-block-heading"><strong>WHAT IS AN API REQUEST?</strong></h4>



<p>REST API request is an HTTP method. It lets you send a request from an endpoint to your server (controller). You can use it if you want to retrieve some information from the server or connected device, or if you want to do some changes (for example to datastore, topology, device, etc..). The most common HTTP methods are GET, PUT, POST or DELETE.</p>



<ul class="wp-block-list"><li><strong>GET</strong>&nbsp;&#8211; used to read data from a server or connected device, when GET is successful you will get 200 OK response</li><li><strong>PUT</strong>&nbsp;&#8211; used to create/update data in a server or connected device, when PUT is successful you should get either 201 Created(if something new was created) or 204 No content(if something was just modified) response</li><li><strong>POST</strong>&nbsp;&#8211; used to send data to a server or connected device ( file upload, customer information, calling RPC, etc&#8230; ), when POST is successful you will get 200 OK response</li><li><strong>DELETE</strong>&nbsp;&#8211; used to remove (delete) data from a server or connected device, when DELETE is successful you will get 204 No content response</li></ul>



<h4 class="wp-block-heading"><strong>PARTS OF REQUESTS</strong></h4>



<p>Default settings for the http://&lt;ip_address&gt;:&lt;port&gt;/ are&nbsp;http://localhost:8888/,&nbsp;but for the purpose of this example, we will use &lt;ip_address&gt;:&lt;port&gt; where ip_address and port are dependent on your running configuration.</p>



<p>The four parts are:</p>



<ul class="wp-block-list"><li>IP Adress &amp; Port Nr.</li><li>Adding RESTCONF/Identifier</li><li>RESTCONF API Path</li><li>Controller Module Path</li></ul>



<p><strong>1.</strong> <span style="text-decoration: underline;">Part of every RESTCONF API request is an IP address and port number,    on which our requested server is running</span>:</p>



<ul class="wp-block-list"><li><strong>http://&lt;ip_address&gt;:&lt;port&gt;/</strong> &#8211; <strong>ip_address</strong>, in this case, is IP address of the server we are sending a request to. <strong>port </strong>is the port number on which the RESTCONF plugin is running.</li></ul>



<p><strong>2.</strong><span style="text-decoration: underline;"> Add RESTCONF/identifier, because we are making requests to it </span>(as described in the&nbsp;<a href="https://tools.ietf.org/html/rfc8040#page-10">RFC 8040</a>):</p>



<ul class="wp-block-list"><li><strong>restconf/</strong>&nbsp;&#8211;&nbsp;is the identifier that we are making a request to via the RESTCONF API</li></ul>



<p><strong>3. </strong><span style="text-decoration: underline;">Path to either data or operations available through RESTCONF API</span></p>



<ul class="wp-block-list"><li><strong>data</strong>&nbsp;(restconf/data/)&nbsp;&#8211;&nbsp;this leads to all data that can be requested, updated or deleted(if those are config data) from the controller datastore</li><li><strong>operations</strong>&nbsp;(restconf/operations) &#8211;&nbsp;this contains all operations(called RPCs &#8211; Remote Procedure Calls) that can be invoked by the user via the RESTCONF interface</li></ul>



<p><strong>4.</strong> <span style="text-decoration: underline;">A path into the desired module in the controller:</span></p>



<ul class="wp-block-list"><li><strong>unified path</strong> &#8211; restconf/data/<strong>module_name:container/</strong> &#8211; where&nbsp;<strong>module_name</strong>&nbsp;is the name of the YANG module and&nbsp;<strong>container&nbsp;</strong>is the container in the particular YANG module</li><li>For example, we can make a&nbsp;request &#8211;&nbsp;restconf/data/network-topology:network-topology/&nbsp;&#8211; which leads to a subtree of data store that is specified as network-topology. It basically returns a network-topology container with all its content</li><li>query parameters&nbsp;(network-topology:network-topology<strong>?content=nonconfig</strong>)&nbsp; &#8211;&nbsp; this is the query that returns data from path into module and container and in this case with query parameter content with value nonconfig that indicates it will return data from path stored only in nonconfig datastore(operational)</li></ul>



<p>You can use zero or more query parameters in the request URI. For example:</p>



<ul class="wp-block-list"><li><strong>content</strong>&nbsp;(in GET) &#8211; to select config or non-config data(stored in configurational or operational data store)</li><li><strong>depth</strong>&nbsp;(in GET) &#8211; limited subtree depth in the reply content</li><li><strong>fields</strong>&nbsp;(in GET) &#8211; a request for a subset of target</li><li><strong>filter</strong>&nbsp;(in GET) &#8211; boolean notification filter for event stream</li><li><strong>insert</strong>&nbsp;(in POST &amp; PUT) &#8211; insertion mode for data resources</li><li><strong>with-defaults</strong>&nbsp;(in GET) &#8211; control the retrieval of default values</li></ul>



<p>If you need more information, take a look at&nbsp;<a href="https://tools.ietf.org/html/rfc8040">RFC 8040.</a></p>



<h4 class="wp-block-heading"><strong>RESPONSE VALUES OF REQUESTS:</strong></h4>



<p>Every request that was made via the REST API, returns a value with return code that indicates success or various types of errors for the request.</p>



<p>There are 5 return code classes:</p>



<ul class="wp-block-list"><li><strong>1xx</strong>&nbsp;&#8211; informational character and indicates for example that request was received and the user should wait for the process, etc.</li><li><strong>2xx</strong>&nbsp;&#8211; indicates that request was received, understood and accepted, for example, 200 OK or 201 Created, etc.</li><li><strong>3xx</strong>&nbsp;&#8211; indicates that additional action has to be performed to finish the request, used mostly in redirections</li><li><strong>4xx</strong>&nbsp;&#8211; indicates an error that might be caused on the client-side, for example, 400 Bad Request, 403 Forbidden, 404 Not Found, etc.</li><li><strong>5xx</strong>&nbsp;&#8211; indicates an error that occurred on the server or that server cannot complete the request for some reason, for example, 500 Internal Server Error, 503 Service Unavailable, etc.</li></ul>



<p>If these codes are insufficient because, for example, the error needs to be described more specifically, then the error message is usually more described and expanded in the return value of the request for example like this:</p>



<pre class="wp-block-code"><code>//Error Response Body
{
    "error": "err-login-01",
    "message": "Login failed",
    "detail": "Check your username and password"
}</code></pre>



<h4 class="wp-block-heading"><strong>EXAMPLES OF SOME REQUESTS FOR POSTMAN:</strong></h4>



<p>Default settings for the&nbsp;<strong>http://&lt;ip_address&gt;:&lt;port&gt;/</strong>&nbsp;are&nbsp;<strong>http://localhost:8888/</strong>,&nbsp;but for example purposes we will use&nbsp;<strong>&lt;ip_address&gt;:&lt;port&gt;</strong>&nbsp;where&nbsp;<strong>ip_address</strong>&nbsp;and&nbsp;<strong>port</strong>&nbsp;are dependent on your running configuration.</p>



<p>Here are models that are used in this example,&nbsp;<strong>custom-yang-rpcs</strong>&nbsp;for simple-sum-rpc and&nbsp;<strong>network-topology</strong>&nbsp;for operations with network topologies and nodes.</p>



<p>custom-yang-rpcs@2019-11-14.yang</p>



<p>network-topology@2013-10-21.yang</p>



<p>To try some requests you can&nbsp;start&nbsp;our&nbsp;<a href="https://lighty.io/">lighty.io</a>&nbsp;example application and example topology (in mininet). An easy way to connect a controller via an HTTP request is using Postman. Here we show you some examples of how to get information from the controller:</p>



<ul class="wp-block-list"><li>to receive the operations(RPCs) that are available in the RESTCONF:</li></ul>



<pre class="wp-block-code"><code>//GET
http://&lt;ip_address>:&lt;port>/restconf/operations</code></pre>



<ul class="wp-block-list"><li>here is the example of the part of the received list of available RESTCONF operations(RPCs) in JSON format :</li></ul>



<pre class="wp-block-code"><code>//GET Response Body
{
    "ietf-restconf:operations": {
        "custom-yang-rpcs:simple-sum-rpc": &#91;
            null
        ],
        "custom-yang-rpcs:custom-netconf-dev-connect": &#91;
            null
        ],
...</code></pre>



<ul class="wp-block-list"><li> To receive a list of available YANG models loaded into the controller </li></ul>



<pre class="wp-block-code"><code>//GET
http://&lt;ip_address>:&lt;port>/restconf/data/ietf-yang-library:modules-state</code></pre>



<ul class="wp-block-list"><li>Here is the example of the part of the received list of YANG models loaded into the controller with its attributes like name, revision, namespace etc.</li></ul>



<pre class="wp-block-code"><code>//GET Response Body
{
    "ietf-yang-library:modules-state": {
        "module": &#91;
            {
                "name": "custom-yang-rpcs",
                "revision": "2019-11-14",
                "namespace": "tag:lighty.io.2019:lighty:custom:yang:rpcs",
                "conformance-type": "import",
                "schema": "/modules/custom-yang-rpcs/2019-11-14"
            },
...</code></pre>



<ul class="wp-block-list"><li> To receive information about our topology </li></ul>



<pre class="wp-block-code"><code>//GET
http://&lt;ip_address>:&lt;port>/restconf/data/network-topology:network-topology?content=nonconfig</code></pre>



<p>If you want to add new topology or node:</p>



<ul class="wp-block-list"><li>To create a new topology with topology-id&nbsp;<em>test-topology.</em>&nbsp;You need to write a body for this method. It is a JSON format with information about a list of network-topology container (topology) and key for this list (test-topology) that has to be unique:</li></ul>



<pre class="wp-block-code"><code>//PUT
http://&lt;ip_address>:&lt;port>/restconf/data/network-topology:network-topology/topology=test-topology</code></pre>



<ul class="wp-block-list"><li> JSON body to PUT network-topology with id&nbsp;<em>test-topology</em> </li></ul>



<pre class="wp-block-code"><code>//PUT Body
{
    "topology":
    {
        "topology-id: "test-topology"
    }
}</code></pre>



<ul class="wp-block-list"><li>Here is the network-topology container in the datastore after a successful PUT request:</li></ul>



<pre class="wp-block-code"><code>//GET Response Body
"network-topology:network-topology": {
    "topology": &#91;
        {
            "topology-id: "test-topology"
        }
    ]
}</code></pre>



<ul class="wp-block-list"><li>Alternatively, we can create the topologies by inserting whole list of topologies as JSON array in the network-topology container, like this(there can be more then three topologies), but it will rewrite whole container, that means every topology that was in there will be erased, so its best for complete lists or empty topologies:</li></ul>



<pre class="wp-block-code"><code>//PUT
http://&lt;ip_address>:&lt;port>/restconf/data/network-topology:network-topology</code></pre>



<ul class="wp-block-list"><li>JSON body to PUT list of topologies </li></ul>



<pre class="wp-block-code"><code>//PUT Body
{
    "network-topology:network-topology": {
        "topology": &#91;
            {
                "topology-id": "test-topology-element1"
            },
            {
                "topology-id": "test-topology-element2"
            },
            {
                "topology-id": "test-topology-element3"
            }
        ]
    }
}</code></pre>



<ul class="wp-block-list"><li>Here is the network-topology container in the datastore after successful PUT request:</li></ul>



<pre class="wp-block-code"><code>//GET Response Body
"network-topology:network-topology": {
    "topology": &#91;
        {
            "topology-id": "test-topology-element1"
        },
        {
            "topology-id": "test-topology-element2"
        },
        {
            "topology-id": "test-topology-element3"
        }
    ]
}</code></pre>



<ul class="wp-block-list"><li>To create a new node in test-topology, you need to write a body for this method. Similarly to the method before, it is a JSON format with information about a topology list (node) and key for this list (test-node):</li></ul>



<pre class="wp-block-code"><code>//PUT
http://&lt;ip_address>:&lt;port>/restconf/data/network-topology:network-topology/topology=test-topology/node=test-node</code></pre>



<ul class="wp-block-list"><li>JSON body to PUT node<em>&nbsp;test-node</em>&nbsp;into network-topology&nbsp;<em>test-topology</em>  (or we can do it with the array of nodes just like in the previous example with the topologies )</li></ul>



<pre class="wp-block-code"><code>//PUT Body
{
    "node": {
        "node-id": "test-node"
    }
}</code></pre>



<p>If you want to delete a topology or node (like before it needs to specify the path to the particular node we want to delete):</p>



<pre class="wp-block-code"><code>//DELETE
http://&lt;ip_address>:&lt;port>/restconf/data/network-topology:network-topology/topology=test-topology/node=test-node</code></pre>



<ul class="wp-block-list"><li>And almost the same as with node, we just specify the path to the topology for deleting: </li></ul>



<pre class="wp-block-code"><code>//DELETE
http://&lt;ip_address>:&lt;port>/restconf/data/network-topology:network-topology/topology=test-topology</code></pre>



<p>You might also invoke RPC that is implemented or you have implemented so when you will register it to lighty controller it will appear in the RESTCONF operations and you can invoke it like this:</p>



<ul class="wp-block-list"><li>I will make an example on custom RPC that takes two input values, sums them up and returns summed value, which is also stored in datastore. You can invoke RPC via POST request like this, you need to specify a path to RPC:</li></ul>



<pre class="wp-block-code"><code>//POST
http://&lt;ip_address>:&lt;port>/restconf/operations/custom-yang-rpcs:simple-sum-rpc</code></pre>



<ul class="wp-block-list"><li> and also JSON body, if RPC has some input values:</li></ul>



<pre class="wp-block-code"><code>//POST RPC Body
{   
    "input": {
        "input-a": 100,
        "input-b": 200
    }
}</code></pre>



<p> It returns output value:</p>



<pre class="wp-block-code"><code>//POST RPC Output Body
{
    "custom-yang-rpcs:output": {
        "output-c": 300
    }
}</code></pre>



<h3 class="wp-block-heading"><strong>SUMMARY</strong></h3>



<p>In this blog post, we covered what are RESTCONF API requests and their basic principles, with a few examples of how to use them. Let&#8217;s do a quick summary:</p>



<ul class="wp-block-list"><li>what is RESTCONF API request and what is it used for(to retrieve or write information from/to server)</li><li>what types of requests RESTCONF API offers and what are the most common ones(GET, PUT, POST, DELETE)</li><li>how can we put together requests based on the models we use(IP address, port, path, query parameters, etc&#8230;)</li><li>that requests have response values which indicate a type of success or failure of request(server fault, user fault, informational character, etc&#8230;)</li><li>examples of GET requests and how GET request return value body can look like</li><li>examples of PUT request, how can we write data to the server with it and how it&#8217;s using JSON as input to particular requests(container, list, etc&#8230;)</li><li>examples of DELETE, how can we delete something from a server(in the example &#8211; topologies, nodes, etc&#8230;)</li><li>example of how can we invoke RPC via a request with input parameters and then what does the output from RPC look like</li></ul>



<p>Those are the basic information that should help you to be able to start using RESTCONF API requests on your own &#8211; basic understanding of how it works, what are they used for and how you can put together your own requests along with where to look for troubleshooting in case of failure.</p>
<p>The post <a href="https://lighty.io/restconf-api-topology-interaction/">[RESTCONF API] Topology Interaction</a> appeared first on <a href="https://lighty.io">lighty.io</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Integrate OpenDaylight Modules into lighty.io</title>
		<link>https://lighty.io/lighty-io-opendaylight-module-integration/</link>
		
		<dc:creator><![CDATA[lighty.io]]></dc:creator>
		<pubDate>Tue, 14 Jan 2020 12:34:57 +0000</pubDate>
				<category><![CDATA[lighty.io]]></category>
		<category><![CDATA[Post]]></category>
		<guid isPermaLink="false">https://lighty.io/?p=1312</guid>

					<description><![CDATA[<p>We will show you how to integrate your favorite OpenDaylight module into lighty.io, using this guide and an OpenFlow module example!</p>
<p>The post <a href="https://lighty.io/lighty-io-opendaylight-module-integration/">Integrate OpenDaylight Modules into lighty.io</a> appeared first on <a href="https://lighty.io">lighty.io</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<h2 class="wp-block-heading">Introduction</h2>



<p>Not every OpenDaylight project is available in lighty.io. Since we are not dependent on the OSGi framework (Karaf), we can&#8217;t simply add and start project features from the Karaf command line. </p>



<p><strong>Here is a list of all&nbsp;<a href="https://wiki-archive.opendaylight.org/view/Project_list">OpenDaylight Projects</a></strong>. Before starting the integration, make sure that your project is not already integrated within lighty.io. </p>



<p><strong>Here is the list of already integrated&nbsp;<a href="https://github.com/PantheonTechnologies/lighty-core/tree/master/lighty-modules">modules</a></strong>. In this article, we will use the <a href="https://github.com/PantheonTechnologies/lighty-core/tree/11.0.x/lighty-modules/lighty-openflow-sb">OpenFlow&nbsp;project&nbsp;</a>as an example of how to integrate the new project to lighty.io. </p>



<p>We have already integrated the OpenFlow project into lighty.io &#8211; it is available under <strong><a href="https://github.com/PantheonTechnologies/lighty-core/tree/11.0.x/lighty-modules/lighty-openflow-sb">lighty-modules/lighty-openflow-sb</a></strong>.</p>



<h1 class="wp-block-heading">Create a new project</h1>



<p>Create a new Java project for your module. In this example, we will be using Maven.</p>



<h1 class="wp-block-heading">Create a new lighty.io module</h1>



<p>Create a new Java class, which will represent new lighty.io module. In our example, we will create the class&nbsp;<a href="https://github.com/PantheonTechnologies/lighty-core/blob/11.0.x/lighty-modules/lighty-openflow-sb/src/main/java/io/lighty/modules/southbound/openflow/impl/OpenflowSouthboundPlugin.java">OpenflowSouthboundPlugin&nbsp;, </a>which corresponds with the OpenFlow module. </p>



<p>lighty.io provides an abstract <strong>AbstractLightyModule class</strong>, containing methods to start and shut down a module. By extending the AbstractLightyModule, you only need to implement two abstract methods:</p>



<ul class="wp-block-list"><li><em>initProcedure</em>&nbsp;</li></ul>



<ul class="wp-block-list"><li><em>stopProcedure</em>&nbsp;</li></ul>



<p>to initialize/stop services &amp; beans in your module.&nbsp;Additionall,y we recommend to use <strong>Builder pattern</strong> to create instances of your new module, in case your module requires a larger amount of input parameters.</p>



<h1 class="wp-block-heading">Initialize Beans &amp; Services</h1>



<p>This section will give you hints on how to find all beans and services from the original project, that you may need to start in your new lighty.io module.</p>



<h4 class="wp-block-heading">Clone OpenDaylight Project</h4>



<p>Clone the project from&nbsp;<a href="https://git.opendaylight.org/gerrit/#/admin/projects/">opendaylight-gerrit</a>&nbsp;repository. Check out the version you would like to integrate. </p>



<h4 class="wp-block-heading">Find all necessary Blueprint files</h4>



<p>Check all project features for blueprint files. Usually, you&#8217;re looking for the&nbsp;<strong><em>autowire.xml</em>&nbsp;</strong>file, which is located in the project: </p>



<p><em>target/generated-sources/blueprint/OSGI-INF.blueprint/autowire.xml</em></p>



<p>This file is generated during the build from the annotations and blueprint .xml files.&nbsp;In the project are blueprint files usually located in:</p>



<p>s<em>rc/main/resources/OSGI-INF.blueprint</em>&nbsp;</p>



<p>Here is the example of the <strong>interfacemanager-impl </strong>feature&nbsp;<em>autowire.xml</em>&nbsp;file from the genius module project. </p>



<pre class="wp-block-code"><code>&lt;?xml version="1.0" encoding="UTF-8"?>&lt;blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0">
    &lt;bean id="alivenessMonitorListenerImpl" class="org.opendaylight.genius.interfacemanager.listeners.AlivenessMonitorListenerImpl" init method="start" destroy-method="close">
        &lt;argument ref="dataBroker"/>
        &lt;argument ref="notificationService"/>
    &lt;/bean>    
	&lt;bean id="ifmDiagStatusProvider" class="org.opendaylight.genius.interfacemanager.diagstatus.IfmDiagStatusProvider" destroy-method="close">
        &lt;argument ref="diagStatusService"/>
    &lt;/bean>
	&lt;bean id="interfacemgrProvider" class="org.opendaylight.genius.interfacemanager.InterfacemgrProvider" destroy-method="close">
        &lt;argument ref="dataBroker"/>
        &lt;argument ref="entityOwnershipService"/>
        &lt;argument ref="idManagerService"/>
        &lt;argument ref="interfaceManagerRpcService"/>
        &lt;argument ref="jobCoordinator"/>
        &lt;argument ref="interfaceManagerCommonUtils"/>
        &lt;argument ref="interfaceMetaUtils"/>
        &lt;argument ref="ifmConfig"/>
        &lt;argument ref="ifmDiagStatusProvider"/>
    &lt;/bean> 
	&lt;service ref="ifmDiagStatusProvider" interface="org.opendaylight.infrautils.diagstatus.ServiceStatusProvider"/
&lt;/blueprint></code></pre>



<p>As you can see, <strong>it contains 3 beans</strong>, where&nbsp;<em>IfmDiagStatusProvider</em>&nbsp;is a service. We need to create them within our lighty.io module project. Bean <em>AlivenessMonitorListenerImpl</em>&nbsp;has <strong>init </strong>and <strong>destroy </strong>methods, which we need to call as well &#8211; usually in the&nbsp;<em>initProcedure</em>&nbsp;and&nbsp;<em>stopProcedure&nbsp;</em>methods.&nbsp;</p>



<p>Sometimes, beans require classes from other projects. Always check beforehand, if the required class isn&#8217;t already being created in one of the present lighty.io modules. <strong>If it&#8217;s there, don&#8217;t create it in your module</strong> &#8211; just pass it to the module as a dependency. Some beans are also created by the builder pattern, which needs to set up class attributes to specific values. Check if the project has a resource file under&nbsp;<em>src/main/resources/initial/config-file.xml</em>, which contains the default values. </p>



<h4 class="wp-block-heading">Create Beans &amp; initProcedure</h4>



<p>In the&nbsp;<em>initProcedure</em>,&nbsp;we are going to initialize all necessary classes, which are in the blueprints. Here is a snippet of the OpenFlow plugin method:</p>



<pre class="wp-block-code"><code>protected boolean initProcedure() {
    ForwardingPingPongDataBroker forwardingPingPongDataBroker =
          new ForwardingPingPongDataBroker(lightyServices.getBindingDataBroker());
    SwitchConnectionProviderList switchConnectionProviders = new SwitchConnectionProviderList(providers);
	this.mastershipChangeServiceManager = new MastershipChangeServiceManagerImpl();
    final OpenflowDiagStatusProvider diagStat = new OpenflowDiagStatusProviderImpl(this.lightyServices
          .getDiagStatusService());
    this.openFlowPluginProvider = new OpenFlowPluginProviderImpl(
          this.configurationService,
          switchConnectionProviders,
          forwardingPingPongDataBroker,
          this.lightyServices.getRpcProviderService(),
          this.lightyServices.getBindingNotificationPublishService(),
          this.lightyServices.getClusterSingletonServiceProvider(),
          this.lightyServices.getEntityOwnershipService(),
          this.mastershipChangeServiceManager, diagStat,
          this.lightyServices.getSystemReadyMonitor());
    this.openFlowPluginProvider.initialize();
...</code></pre>



<p><strong>We are creating 2 classes</strong> from the OpenFlow blueprints directly in the&nbsp;<em>initProcedure</em>. The&nbsp;<em>OpenFlowPluginProviderImpl</em>&nbsp;class requires some dependencies, which are provided by <strong>lightyServices </strong>&#8211; located in the lighty controller module. We are also calling the initialize method on the bean as well. </p>



<h4 class="wp-block-heading">Close Beans in the stopProcedure</h4>



<p>In <em>stopProcedure</em>,&nbsp;we are going to call the destroy-methods on all beans, which have it described in the blueprints. </p>



<pre class="wp-block-code"><code>@Override
protected boolean stopProcedure() {
    destroy(this.packetListenerNotificationRegistration);
    destroy(this.flowCapableTopologyProvider);
    destroy(this.operationProcessor);
    destroy(this.forwardingRulesManagerImpl);
    destroy(this.arbitratorReconciliationManager);
    destroy(this.openFlowPluginProvider);
    destroy(this.mastershipChangeServiceManager);
    destroy(this.terminationPointChangeListener);
    destroy(this.nodeChangeListener);
    return true;
}</code></pre>



<h1 class="wp-block-heading">Runnable application with the new module</h1>



<p>A lighty.io application is basically just a plain old Java&nbsp;<strong><em>main</em>&nbsp;</strong>method, that will run your module and all necessary dependencies.&nbsp;In order to create an application for your module, simply create and start all the necessary dependencies in the&nbsp;<em><strong>main</strong></em>&nbsp;method&nbsp;first, and then create and start your module. </p>



<p>We are now going to show you, how we have made the <a href="https://github.com/PantheonTechnologies/lighty-core/blob/master/lighty-examples/lighty-community-restconf-ofp-app/src/main/java/io/lighty/examples/controllers/restconf/ofp/Main.java">example OpenFlow application</a>. First step is to <strong>get the configuration of the modules:</strong></p>



<pre class="wp-block-code"><code>
final Set&lt;YangModuleInfo> modelPaths = Stream.concat(RestConfConfigUtils.YANG_MODELS.stream(),
	OpenflowConfigUtils.OFP_MODELS.stream())
	.collect(Collectors.toSet());
controllerConfiguration = ControllerConfigUtils.getDefaultSingleNodeConfiguration(modelPaths);
restConfConfiguration =  RestConfConfigUtils.getDefaultRestConfConfiguration();
openflowpluginConfiguration = OpenflowConfigUtils.getDefaultOfpConfiguration();</code></pre>



<p>After we have the required configuration, we can <strong>start the modules</strong> one after the other.</p>



<pre class="wp-block-code"><code>//1. initialize and start Lighty controller (MD-SAL, Controller, YangTools, Akka)
final LightyControllerBuilder lightyControllerBuilder = new LightyControllerBuilder();
final LightyController lightyController = lightyControllerBuilder.from(controllerConfiguration).build();
lightyController.start().get();
//2. start RESTCONF server
final CommunityRestConfBuilder communityRestConfBuilder = new CommunityRestConfBuilder();
final CommunityRestConf communityRestConf = communityRestConfBuilder.from(RestConfConfigUtils
	.getRestConfConfiguration(restConfConfiguration, lightyController.getServices()))
	.build();
communityRestConf.start();
//3. start OpenFlow SBP
final OpenflowSouthboundPlugin plugin;
plugin = new OpenflowSouthboundPluginBuilder()
	.from(configuration, lightyController.getServices())
	.withPacketListener(new PacketInListener())
	.build();
ListenableFuture&lt;Boolean> start = plugin.start();</code></pre>



<p>Check out the example&nbsp;<a href="https://github.com/PantheonTechnologies/lighty-core/tree/master/lighty-examples">applications&nbsp;</a>in lighty.io <a href="https://lighty.io/use-cases-for-lighty-io/">or other articles</a>, for more information.</p>



<h1 class="wp-block-heading">Summary</h1>



<p>In this article, we have described the way to include other OpenDaylight projects, which are not integrated into our lighty.io. Steps of integrating the new module were:</p>



<ul class="wp-block-list"><li><strong>Creating </strong>new project for the module</li><li><strong>Initializing </strong>module classes from blueprints</li><li><strong>Creating </strong>the runnable application in which a new module started</li></ul>



<p>Don&#8217;t forget, <strong>some classes require dependencies from another module and its recommended to use existing implementations if they are available in lighty.io.</strong></p>



<p>by Peter Válka</p>
<p>The post <a href="https://lighty.io/lighty-io-opendaylight-module-integration/">Integrate OpenDaylight Modules into lighty.io</a> appeared first on <a href="https://lighty.io">lighty.io</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Spring.io Integration</title>
		<link>https://lighty.io/lighty-io-brings-opendaylight-to-spring-io-developers/</link>
		
		<dc:creator><![CDATA[lighty.io]]></dc:creator>
		<pubDate>Fri, 08 Jun 2018 09:25:37 +0000</pubDate>
				<category><![CDATA[lighty.io]]></category>
		<category><![CDATA[Post]]></category>
		<guid isPermaLink="false">https://lighty.io/?p=835</guid>

					<description><![CDATA[<p>lighty.io has been enabling OpenDaylight (ODL) components and applications to run in various environments and frameworks. Those components and applications have never been useable by ODL developers before. Spring.io&#160;is a popular java ecosystem for application developers. Wouldn&#8217;t it be perfect to enable lighty.io for Spring as the target runtime environment<a class="moretag" href="https://lighty.io/lighty-io-brings-opendaylight-to-spring-io-developers/"> Read more</a></p>
<p>The post <a href="https://lighty.io/lighty-io-brings-opendaylight-to-spring-io-developers/">Spring.io Integration</a> appeared first on <a href="https://lighty.io">lighty.io</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p><img fetchpriority="high" decoding="async" src="https://testsite.lighty.io/wp-content/uploads/2018/06/rovnica-2-1024x220.png" alt="" width="494" height="106" class="aligncenter"></p>
<p style="text-align: justify;">lighty.io has been enabling OpenDaylight (ODL) components and applications to run in various environments and frameworks.</p>
<p style="text-align: justify;">Those components and applications have never been useable by ODL developers before. <a href="https://spring.io/" target="_blank" rel="noopener noreferrer">Spring.io&nbsp;</a>is a popular java ecosystem for application developers. Wouldn&#8217;t it be perfect to enable lighty.io for Spring as the target runtime environment is Java SE? This is exactly what we did.</p>
<p style="text-align: justify;">lighty.io provides dependency injection extensions for Spring. That makes it easy to consume ODL core services via Spring&#8217;s dependency injection system. Let&#8217;s check how simple it is to create an OpenDaylight based NETCONF SDN controller application in the spring-boot environment.</p>
<p>The architecture of this example is in the picture.</p>
<p><img decoding="async" src="https://testsite.lighty.io/wp-content/uploads/2018/06/lighty-spring-architecture.png"></p>
<h3>Generate Spring Boot Skeleton Project</h3>
<p>First, generate the Maven Spring Boot skeleton application with start.spring.io. In this guide, we will use Spring Boot release 2.0.2.</p>
<p>For now, we will need only standard web dependency, as we want to expose some REST endpoints.</p>
<p>Let&#8217;s use inputs as follows:</p>
<p style="padding-left: 30px;"><strong>group id</strong>: io.lighty.core<br />
<strong>artifact id</strong>: lighty-controller-springboot<br />
<strong>name</strong>: lighty-controller-springboot<br />
<strong>description</strong>: Demo lighty.io project for Spring Boot<br />
<strong>package</strong>: io.lighty.core.controller.springboot<br />
<strong>packaging</strong>: jar<br />
<strong>java version</strong>: 8</p>
<p><em>Start.spring.io</em> generates for us a basic maven project hierarchy with an application entry point in class <em>LightyControllerSpringbootApplication</em>.</p>
<h3>lighty.io Project Setup</h3>
<p>Next, we need to <strong>start lighty.io inside Sprin</strong>g, so just simply add lighty.io dependency injection extension for Spring to pom.xml.</p>
<p>This artifact is a bean provider for Spring&#8217;s <strong>@Configuration</strong>.</p>
<pre data-enlighter-language="xml" data-enlighter-theme="enlighter"> 	 	 	 	<lighty.version>8.0.0-SNAPSHOT</lighty.version>
<dependency>
    <groupid>io.lighty.core</groupid>
    <artifactid>lighty-controller-spring-di</artifactid>
    <version>${lighty.version}</version>
</dependency></pre>
<p>And to use the default single node lighty.io configuration add a dependency</p>
<pre data-enlighter-language="xml" data-enlighter-theme="enlighter"><dependency>
    <groupid>io.lighty.resources</groupid>
    <artifactid>singlenode-configuration</artifactid>
    <version>${lighty.version}</version>
</dependency></pre>
<p>For the NETCONF devices, we will need also the NETCONF Southbound module</p>
<pre data-enlighter-language="xml" data-enlighter-theme="enlighter"><dependency>
    <groupid>io.lighty.modules.southbound.netconf</groupid>
    <artifactid>lighty-netconf-sb</artifactid>
    <version>${lighty.version}</version>
</dependency></pre>
<p>Since now we have lighty-core on the classpath, let&#8217;s create lighty.io bean definitions for Spring.</p>
<p style="text-align: justify;">Create new <strong>@Configuration</strong> class <strong>LightyConfiguration</strong> extending <strong>LightyCoreSpringConfiguration</strong> which initializes all the lighty.io services as Spring beans. To be able to initialize all lighty.io services it is necessary to create lighty.io core controller as Spring bean, for example in class <strong>LightyConfiguration</strong>. In this example, we need to initialize <em>LightyController</em> and <em>NETCONF Southbound Plugin</em> too.</p>
<pre data-enlighter-language="java" data-enlighter-theme="enlighter">@Configuration
public class LightyConfiguration extends LightyCoreSpringConfiguration {
    private static final Logger LOG = LoggerFactory.getLogger(LightyConfiguration.class);
    @Bean
    LightyController initLightyController() throws Exception {
        LOG.info("Building LightyController Core");
        final LightyControllerBuilder lightyControllerBuilder = new LightyControllerBuilder();
        final Set<yangmoduleinfo> mavenModelPaths = new HashSet&lt;&gt;();
        mavenModelPaths.addAll(NetconfConfigUtils.NETCONF_TOPOLOGY_MODELS);
        mavenModelPaths.add($YangModuleInfoImpl.getInstance()); //Add toaster model
        final LightyController lightyController = lightyControllerBuilder
            .from(ControllerConfigUtils.getDefaultSingleNodeConfiguration(mavenModelPaths))
            .build();
        LOG.info("Starting LightyController (waiting 10s after start)");
        final ListenableFuture<boolean> started = lightyController.start();
        started.get();
        LOG.info("LightyController Core started");
        return lightyController;
    }
    @Bean
    NetconfSBPlugin initNetconfSBP(LightyController lightyController) throws ExecutionException, InterruptedException {
        final NetconfConfiguration netconfSBPConfiguration = NetconfConfigUtils.injectServicesToTopologyConfig(
            NetconfConfigUtils.createDefaultNetconfConfiguration(), lightyController.getServices());
        NetconfTopologyPluginBuilder netconfSBPBuilder = new NetconfTopologyPluginBuilder();
        final NetconfSBPlugin netconfSouthboundPlugin = netconfSBPBuilder
            .from(netconfSBPConfiguration, lightyController.getServices())
            .build();
        netconfSouthboundPlugin.start().get();
        return netconfSouthboundPlugin;
    }
}</boolean></yangmoduleinfo></pre>
<p>From this point, we have created bean definitions for the Spring environment. Let&#8217;s add some basic logic.</p>
<h3>Create a Basic lighty.io REST Service</h3>
<p>In this step, we will create a simple REST service, exposing endpoints for an example of managing NETCONF devices.</p>
<p>Let&#8217;s add endpoints which provide us functionality to:</p>
<ul>
<li><strong>connect</strong> to a device</li>
<li><strong>list</strong> all devices</li>
<li><strong>disconnect</strong> device</li>
</ul>
<p>Simply create a <strong>@RestController</strong> class skeleton for REST endpoints returning some default responses.</p>
<pre data-enlighter-language="java" data-enlighter-theme="enlighter">@RestController
@RequestMapping(path = "netconf")
public class NetconfDeviceRestService {
    @GetMapping(path = "/list")
    public ResponseEntity getNetconfDevicesIds() {
        // TODO add endpoin impl
        return ResponseEntity.noContent().build();
    }
    @PutMapping(path = "/id/{netconfDeviceId}")
    public ResponseEntity connectNetconfDevice(@PathVariable final String netconfDeviceId,
                                               @RequestBody final NetconfDeviceRequest deviceInfo) {
        // TODO add endpoin impl
        return ResponseEntity.noContent().build();
    }
    @DeleteMapping(path = "/id/{netconfDeviceId}")
    public ResponseEntity disconnectNetconfDevice(@PathVariable final String netconfDeviceId) {
        // TODO add endpoin impl
        return ResponseEntity.noContent().build();
    }
}</pre>
<ul>
<li><strong>GET /netconf/list</strong> will accept no attributes and returns all stored NETCONF devices</li>
<li><strong>PUT /netconf/id/{netconfDeviceId}</strong> will need device ID and <em><strong>device details</strong></em> needed to connect contained in the request body</li>
<li><strong>DELETE /netconf/id/{netconfDeviceId}</strong> will disconnect device and removed it from datastore</li>
</ul>
<p style="text-align: justify;">All lighty.io core services are already defined as beans, so we can inject <strong>DataBroker</strong> and <strong>MountPointService</strong> into our REST Service class <strong>NetconfDeviceRestService</strong>, to provide access to OpenDaylight&#8217;s global data store.</p>
<pre data-enlighter-language="java" data-enlighter-theme="enlighter">@Autowired
@Qualifier("BindingDataBroker")
private DataBroker dataBroker;
@Autowired
private MountPointService mountPointService;</pre>
<p>Now we can write and read from datastore so let&#8217;s update endpoints implementations in class <strong>NetconfDeviceRestService</strong>:</p>
<pre data-enlighter-language="java" data-enlighter-theme="enlighter">private static final InstanceIdentifier<topology> NETCONF_TOPOLOGY_IID = InstanceIdentifier
        .create(NetworkTopology.class)
        .child(Topology.class, new TopologyKey(new TopologyId("topology-netconf")));
private static final long TIMEOUT = 1;
@GetMapping(path = "/list")
public ResponseEntity getNetconfDevicesIds() throws InterruptedException, ExecutionException, TimeoutException {
    try (final ReadOnlyTransaction tx = dataBroker.newReadOnlyTransaction()) {
        final Optional<topology> netconfTopoOptional =
            tx.read(LogicalDatastoreType.OPERATIONAL, NETCONF_TOPOLOGY_IID).get(TIMEOUT, TimeUnit.SECONDS);
        if (netconfTopoOptional.isPresent() &amp;&amp; netconfTopoOptional.get().getNode() != null) {
            final List<netconfdeviceresponse> response = new ArrayList&lt;&gt;();
            for (Node node : netconfTopoOptional.get().getNode()) {
                final NetconfDeviceResponse nodeResponse = NetconfDeviceResponse.from(node);
                response.add(nodeResponse);
                final Optional<mountpoint> netconfMountPoint =
                    mountPointService.getMountPoint(
                        NETCONF_TOPOLOGY_IID.child(Node.class, new NodeKey(node.getNodeId()))
                    );
                if (netconfMountPoint.isPresent()) {
                    final Optional<databroker> netconfDataBroker =
                        netconfMountPoint.get().getService(DataBroker.class);
                    if (netconfDataBroker.isPresent()) {
                        final ReadOnlyTransaction netconfReadTx =
                            netconfDataBroker.get().newReadOnlyTransaction();
                        final Optional<toaster> toasterData = netconfReadTx
                            .read(LogicalDatastoreType.OPERATIONAL, TOASTER_IID).get(TIMEOUT, TimeUnit.SECONDS);
                        if (toasterData.isPresent() &amp;&amp; toasterData.get().getDarknessFactor() != null) {
                            nodeResponse.setDarknessFactor(toasterData.get().getDarknessFactor());
                        }
                    }
                }
            }
            return ResponseEntity.ok(response);
        } else {
            return ResponseEntity.notFound().build();
        }
    }
}
@PutMapping(path = "/id/{netconfDeviceId}")
public ResponseEntity connectNetconfDevice(@PathVariable final String netconfDeviceId,
                                           @RequestBody final NetconfDeviceRequest deviceInfo)
    throws InterruptedException, ExecutionException, TimeoutException {
    final WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
    final NodeId nodeId = new NodeId(netconfDeviceId);
    final InstanceIdentifier<node> netconfDeviceIID = NETCONF_TOPOLOGY_IID
        .child(Node.class, new NodeKey(nodeId));
    final Node netconfDeviceData = new NodeBuilder()
        .setNodeId(nodeId)
        .addAugmentation(NetconfNode.class, new NetconfNodeBuilder()
            .setHost(new Host(new IpAddress(new Ipv4Address(deviceInfo.getAddress()))))
            .setPort(new PortNumber(deviceInfo.getPort()))
            .setCredentials(new LoginPasswordBuilder()
                    .setUsername(deviceInfo.getUsername())
                    .setPassword(deviceInfo.getPassword())
                    .build())
            .setTcpOnly(false)
            .build())
        .build();
    tx.put(LogicalDatastoreType.CONFIGURATION, netconfDeviceIID, netconfDeviceData);
    tx.submit().get(TIMEOUT, TimeUnit.SECONDS);
    return ResponseEntity.ok().build();
}
@DeleteMapping(path = "/id/{netconfDeviceId}")
public ResponseEntity disconnectNetconfDevice(@PathVariable final String netconfDeviceId)
    throws InterruptedException, ExecutionException, TimeoutException {
    final WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
    final NodeId nodeId = new NodeId(netconfDeviceId);
    final InstanceIdentifier<node> netconfDeviceIID = NETCONF_TOPOLOGY_IID
        .child(Node.class, new NodeKey(nodeId));
    tx.delete(LogicalDatastoreType.CONFIGURATION, netconfDeviceIID);
    tx.submit().get(TIMEOUT, TimeUnit.SECONDS);
    return ResponseEntity.ok().build();
}</node></node></toaster></databroker></mountpoint></netconfdeviceresponse></topology></topology></pre>
<p>Be sure you added the device yang model to <strong>PROJECT_WORKING_DIR/cache/schema/toaster@2009-11-20.yang</strong> (<a href="https://github.com/YangModels/yang/blob/19fea483099dbf2864b3c3186a789d12d919f4db/experimental/odp/toaster.yang" target="_blank" rel="noopener noreferrer">toaster@2009-11-20.yang</a>).</p>
<h3>Read Data from the NETCONF Device</h3>
<p><strong>Test the application through created REST endpoints</strong>:</p>
<ul>
<li>start the Spring application</li>
<li>connect to NETCONF device with ID <em>testDevice</em></li>
</ul>
<pre data-enlighter-language="java" data-enlighter-theme="enlighter">curl -X PUT 
  http://localhost:8080/netconf/id/testDevice 
  -H 'Accept: application/json' 
  -H 'Content-Type: application/json' 
  -d '{
    "username": "admin",
    "password": "admin",
    "address": "127.0.0.1",
    "port": "17830"
}'</pre>
<ul>
<li>list all NETCONF devices</li>
</ul>
<pre data-enlighter-language="java" data-enlighter-theme="enlighter">curl -X GET 
  http://localhost:8080/netconf/list 
  -H 'Accept: application/json' 
  -H 'Content-Type: application/json'</pre>
<p>if the connection was successful, the response will be</p>
<pre data-enlighter-language="java" data-enlighter-theme="enlighter">[
    {
        "nodeId": "testDevice",
        "connectionStatus": "Connected",
        "darknessFactor": 1000
    }
]</pre>
<p>Notice that the <em>darknessFactor</em> was read from the NETCONF device. Our testing device supports <a href="https://github.com/YangModels/yang/blob/19fea483099dbf2864b3c3186a789d12d919f4db/experimental/odp/toaster.yang">model <strong>toaster-model</strong> from OpenDaylight</a>&nbsp;so we were able to read the value defined in the model through <strong>MountPoint</strong>.</p>
<p>Michal Baník</p>
<p>The post <a href="https://lighty.io/lighty-io-brings-opendaylight-to-spring-io-developers/">Spring.io Integration</a> appeared first on <a href="https://lighty.io">lighty.io</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>lighty.io Authentication Authorization &#038; Accounting</title>
		<link>https://lighty.io/aaa-integration/</link>
		
		<dc:creator><![CDATA[lighty.io]]></dc:creator>
		<pubDate>Thu, 07 Jun 2018 10:19:34 +0000</pubDate>
				<category><![CDATA[lighty.io]]></category>
		<category><![CDATA[Post]]></category>
		<guid isPermaLink="false">https://lighty.io/?p=819</guid>

					<description><![CDATA[<p>Do you need an SDN controller that you can run quickly? Is security one of your concerns? Do you need to divide the users into groups &#38; restrict their capabilities for certain tasks? With lighty.io AAA, you can create password-protected users. You can assign a role and a domain and<a class="moretag" href="https://lighty.io/aaa-integration/"> Read more</a></p>
<p>The post <a href="https://lighty.io/aaa-integration/">lighty.io Authentication Authorization &#038; Accounting</a> appeared first on <a href="https://lighty.io">lighty.io</a>.</p>
]]></description>
										<content:encoded><![CDATA[<ul>
<li style="text-align: left;">Do you need an <strong>SDN controller</strong> that you can run <strong>quickly</strong>?</li>
<li style="text-align: left;">Is <strong>security</strong> one of your concerns?</li>
<li style="text-align: left;">Do you need to divide the users into <strong>groups</strong> &amp; <strong>restrict</strong> <strong>their capabilities</strong> for certain tasks?</li>
</ul>
<p style="text-align: left;">With lighty.io AAA, you can create password-protected users. You can assign a role and a domain and define its capabilities. You can restrict users to a certain method or permit them to access data only on a specific path.</p>
<h3 style="text-align: center;"><img decoding="async" src="https://lighty.io/wp-content/uploads/2018/06/Scheme-AAA-filtering-1024x658.png" alt="" width="702" height="451"></h3>
<h4>Use this dependency to give lighty.io AAA a try:</h4>
<pre data-enlighter-language="xml" data-enlighter-theme="enlighter"><dependency>
   <groupid>io.lighty.aaa</groupid>
   <artifactid>lighty-aaa</artifactid>
   <version>8.0.0-SNAPSHOT</version>
</dependency>
</pre>
<p>To start this module, simply create a <b>lighty AAA object</b> and call a start method. You can use the shutdown method to stop this module. Once the lighty controller &amp; RestConf with lighty AAA are up and running, you may start to create new users, roles, and domains.</p>
<p>You can assign roles to the users, create policies for, and grant permissions to the users.</p>
<hr>
<h2 style="text-align: center;"><strong>How to create a user</strong></h2>
<hr>
<p>Use this POST request to create a user:</p>
<p data-enlighter-language="json" data-enlighter-theme="enlighter" style="line-height: 1.42857;"><em>path: </em><ip><port>/auth/v1/users</port></ip></p>
<p><b>with body:</b></p>
<pre data-enlighter-language="json" data-enlighter-theme="enlighter">{
    "name": "u1",
    "description": "just another new user",
    "enabled": 1,
    "email": "u1@sdn.tech",
    "password": "foo",
    "salt": "foo",
    "domainid": "sdn"
}</pre>
<p>lighty will automatically generate a user id for you and save it into the database. The expected response should be &#8220;<b>201 Created</b>&#8220;:</p>
<pre data-enlighter-language="json" data-enlighter-theme="enlighter">{
    "userid": "u1@sdn",
    "name": "u1",
    "description": "just another new user",
    "enabled": 1,
    "email": "u1@sdn.tech",
    "password": "**********",
    "salt": "**********",
    "domainid": "sdn"
}</pre>
<hr>
<h2 style="text-align: center;">How to list users</h2>
<hr>
<p>This GET request should bring up a list of users with their information:</p>
<p data-enlighter-language="json" data-enlighter-theme="enlighter" style="line-height: 1.42857;"><em>path: </em><ip><port>/auth/v1/users</port></ip></p>
<p>Now we expect a response with a list of users with their information, &#8220;<b>200 OK&#8221;.</b></p>
<pre data-enlighter-language="json" data-enlighter-theme="enlighter">{
    "users": [
        {
            "userid": "admin@sdn",
            "name": "admin",
            "description": "admin user",
            "enabled": 1,
            "email": "",
            "password": "**********",
            "salt": "**********",
            "domainid": "sdn"
        },
        {
            "userid": "u1@sdn",
            "name": "u1",
            "description": "just another new user",
            "enabled": 1,
            "email": "u1@sdn.tech",
            "password": "**********",
            "salt": "**********",
            "domainid": "sdn"
        }
    ]
}</pre>
<p>If we use the credentials of this newly created user, we would receive the response &#8216;<b>unauthorized</b>&#8216;. To resolve this issue, we need to<b> create a &#8220;grant&#8221;&nbsp;</b>to the user. This means that we have to assign a role to the user.</p>
<hr>
<h2 style="text-align: center;">How to create a &#8220;grant&#8221;</h2>
<hr>
<p>Use this POST request to create a grant:</p>
<p data-enlighter-language="json" data-enlighter-theme="enlighter" style="line-height: 1.42857;"><em>path: </em><ip><port>/auth/v1/domains/<domain-id>/users/<user-id>/roles</user-id></domain-id></port></ip></p>
<p>with the body:</p>
<pre data-enlighter-language="json" data-enlighter-theme="enlighter">{
    "roleid": "<role-id>"
}
</role-id></pre>
<p>lighty will process this request, by writing new data to grant a table of the database with specific user-id and role-id under the chosen domain. The expected response should be the following: 201 Created</p>
<pre data-enlighter-language="json" data-enlighter-theme="enlighter">{
    "grantid": "<user-id>@<role-id>@<domain-id>",
    "domainid": "<domain-id>",
    "userid": "<user-id>",
    "roleid": "<role-id>"
}</role-id></user-id></domain-id></domain-id></role-id></user-id></pre>
<hr>
<h2 style="text-align: center;">How to list roles</h2>
<hr>
<p>This GET request will bring up a list of roles with their information.</p>
<p data-enlighter-language="json" data-enlighter-theme="enlighter" style="line-height: 1.42857;"><em>path: </em><ip><port>/auth/v1/roles</port></ip></p>
<p>Now we expect a response with a list of roles with their information, <b>&#8220;200 OK&#8221;.</b></p>
<pre data-enlighter-language="json" data-enlighter-theme="enlighter">{
    "roles": [
        {
            "roleid": "admin@sdn",
            "name": "admin",
            "description": "a role for admins",
            "domainid": "sdn"
        },
        {
            "roleid": "user@sdn",
            "name": "user",
            "description": "a role for users",
            "domainid": "sdn"
        }
    ]
}</pre>
<p>This is perfect if we need to <b>divide our users</b> into an admin role which would have the capability to create, remove, and update users. The user role would have the capability to do operations on datastore.</p>
<p>But what if <b>we</b> <b>need to create more roles</b>? Such as a role where the user can only read data or a role where the user can do operations only on a specific path. To do that, we need to follow these two steps:</p>
<p><b>1: Create a new role<br />
2: Define a policy for the role</b></p>
<hr>
<h2 style="text-align: center;"><strong>How to create a role</strong></h2>
<hr>
<p>Use this POST request to create a role:´</p>
<p data-enlighter-language="json" data-enlighter-theme="enlighter" style="line-height: 1.42857;">path: <ip><port>/auth/v1/roles</port></ip></p>
<p>with body:</p>
<pre data-enlighter-language="json" data-enlighter-theme="enlighter">{
    "name" : "read-only",
    "description": "This role is for users that have read only rights",
    "domainid": "sdn"
}
</pre>
<p>Lighty will write this role to the roles table in the database so it can be used to assign this role to the user or to update policy for this role. When creating a role we expect the following response: <strong>201 Created.</strong></p>
<pre data-enlighter-language="json" data-enlighter-theme="enlighter">{
    "roleid": "read-only@sdn",
    "name": "read-only",
    "description": "This role is for users that have read only rights",
    "domainid": "sdn"
}
</pre>
<hr>
<h2 style="text-align: center;"><strong>How to define a policy for a specific role</strong></h2>
<hr>
<p>The meaning of defining a policy to a role is to manage what the given role can do. By defining a policy you can restrict a role; to use specific HTTP methods or access data only under a specific list or container.</p>
<p>Create a POST request to define a policy:</p>
<p data-enlighter-language="json" data-enlighter-theme="enlighter" style="line-height: 1.42857;"><em>path: </em><ip><port>/restconf/data/aaa:http-authorization/policies</port></ip></p>
<p>with body:</p>
<pre data-enlighter-language="json" data-enlighter-theme="enlighter">{
    "policies": [
      {
        "resource": "/restconf/modules/**",
        "permissions": [
          {
            "role": "read-only",
            "actions": [
             "get"
            ]
          }
        ],
        "description": "read only policy on restconf/modules list"
      }
    ]
}
</pre>
<p>After this request, all the users who have assigned the role of &#8220;read-only&#8221;, will be able to do only GET request on path <ip><port><b>/restconf/modules </b>and<b> </b>what <b>&#8220;modules&#8221; contains.</b></port></ip></p>
<hr>
<h2 style="text-align: center;"><strong>How to list policies</strong></h2>
<hr>
<p>Use the following GET request to see all the policies which are created:<br />
path: <strong><ip><port>/restconf/data/aaa:http-authorization/policies</port></ip></strong></p>
<p>Now we expect a response with a list of policies with their information:<br />
200 OK</p>
<pre data-enlighter-language="json" data-enlighter-theme="enlighter">{
    "policies": {
        "policies": [
            {
                "resource": "/restconf/modules/**",
                "permissions": [
                    {
                        "role": "read-only",
                        "actions": [
                            "get"
                        ]
                    }
                ],
                "description": "read only policy on restconf/modules list"
            },
            {
                "resource": "/restconf/**",
                "permissions": [
                    {
                        "role": "users",
                        "actions": [
                            "get"
                        ]
                    }
                ],
                "description": "read only policy on restconf list"
            }
        ]
    }
}</pre>
<hr>
<h2 style="text-align: center;"><strong>How to create a domain</strong></h2>
<hr>
<p>Use the following POST request to create a new domain:</p>
<p data-enlighter-language="json" data-enlighter-theme="enlighter" style="line-height: 1.42857;"><domain-name> </domain-name><em>path: </em><ip><port>/auth/v1/domains</port></ip></p>
<p><b>with body:</b></p>
<pre data-enlighter-language="json" data-enlighter-theme="enlighter">{
    "name" : "<domain-name>",
    "description": "<domain-description>",
    "enabled": true
}</domain-description></domain-name></pre>
<p>Lighty AAA will create a domain id and this domain will be written into the domains table of the database. The expected response should be the following:</p>
<pre data-enlighter-language="json" data-enlighter-theme="enlighter">{
    "domainid": "<domain-id>",
    "name": "<domain-name>",
    "description": "<domain-description>",
    "enabled": true
}
</domain-description></domain-name></domain-id></pre>
<hr>
<h2 style="text-align: center;"><strong>How to list domains</strong></h2>
<hr>
<p>We can use the following GET request to see all the domains that are created:</p>
<p data-enlighter-language="json" data-enlighter-theme="enlighter" style="line-height: 1.42857;"><em>path: </em><ip><port>/auth/v1/domains</port></ip></p>
<p>Now we expect a response with a list of domains with their information:<br />
200 OK</p>
<pre data-enlighter-language="json" data-enlighter-theme="enlighter">{
    "domains": [
        {
            "domainid": "<domain-id>",
            "name": "<domain-name>",
            "description": "<domain-description>",
            "enabled": true
        },
        {
            "domainid": "<domain-id>",
            "name": "<domain-name>",
            "description": "<domain-description>",
            "enabled": false
        }
    ]
}</domain-description></domain-name></domain-id></domain-description></domain-name></domain-id></pre>
<hr>
<h2 style="text-align: center;"><strong>How to authenticate</strong></h2>
<hr>
<p>There are two ways to authenticate the user:</p>
<p>1: <strong>HTTP basic</strong> authentication<br />
2: <strong>oauth2</strong> to generate tokens</p>
<h5>Method 1: HTTP basic authentication</h5>
<p>For this, we need a username and password separated by column encrypted using base64 encryption. The resulting encryption can be used as a header with <strong>key &#8220;Authorization&#8221;</strong> and <strong>value &#8220;Basic&#8221;.</strong></p>
<h5>Method 2: Oauth2 authentication</h5>
<p>The second option is to generate a Bearer token. To generate a token, create a POST request:</p>
<p>path: <strong>/<ip><port>oauth2/token</port></ip></strong><br />
Content-Type :&nbsp;<strong>application/x-www-form-urlencoded</strong></p>
<p>with body:</p>
<pre data-enlighter-language="raw" data-enlighter-theme="enlighter">grant_type=password&amp;username=<username>&amp;pard=<password>&amp;scope=<domain-name></domain-name></password></username></pre>
<p>Now, you should be ready to use Authentication, Authorization &amp; Accounting with lighty.io.</p>
<p>The post <a href="https://lighty.io/aaa-integration/">lighty.io Authentication Authorization &#038; Accounting</a> appeared first on <a href="https://lighty.io">lighty.io</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Rapid NETCONF Controller Integration Testing</title>
		<link>https://lighty.io/netconf-performance-test/</link>
		
		<dc:creator><![CDATA[lighty.io]]></dc:creator>
		<pubDate>Fri, 04 May 2018 11:02:46 +0000</pubDate>
				<category><![CDATA[lighty.io]]></category>
		<category><![CDATA[Post]]></category>
		<guid isPermaLink="false">https://lighty.io/?p=792</guid>

					<description><![CDATA[<p>Full NETCONF/RESTCONF controller integration test under 12s! Can your SDN controller do that? With lighty.io &#8211; you can. Just like in a high-performance sports car world, the drag race is used to set winners and losers apart. Faster is better, it is as simple as that. In SDN business, you<a class="moretag" href="https://lighty.io/netconf-performance-test/"> Read more</a></p>
<p>The post <a href="https://lighty.io/netconf-performance-test/">Rapid NETCONF Controller Integration Testing</a> appeared first on <a href="https://lighty.io">lighty.io</a>.</p>
]]></description>
										<content:encoded><![CDATA[		<div data-elementor-type="wp-post" data-elementor-id="792" class="elementor elementor-792">
						<section class="elementor-section elementor-top-section elementor-element elementor-element-319ccce5 elementor-section-boxed elementor-section-height-default elementor-section-height-default" data-id="319ccce5" data-element_type="section">
						<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-3ccaa28d" data-id="3ccaa28d" data-element_type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-29eb11af elementor-widget elementor-widget-text-editor" data-id="29eb11af" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
									<article id="post-680" class="section section-text"><h4 style="text-align: center;">Full NETCONF/RESTCONF controller integration test under 12s!</h4><h4 style="text-align: center;">Can <em>your</em> SDN controller do that?</h4><p>With lighty.io you can. Just like in a high-performance sports car world, the drag race is used to set winners and losers apart.</p><p>Faster is better, it is as simple as that. In SDN business, you have to test and re-test really hard before you deploy or deliver to the customer. High-performance integration testing is essential for cutting down the development costs and time-to-market to a minimum but keeping the high quality of the product.</p><p>lighty.io utilizes OpenDaylight components and adds agility and flexibility beyond the upstream OpenDaylight convention. Continuous integration, delivery, and deployment, known collectively as CI/CD, is an integral part of modern development intended to reduce errors during integration and deployment while increasing project velocity.</p><p>CI/CD is a philosophy and set of practices often augmented by robust tooling that emphasize automated testing at each stage of the software pipeline. CI/CD pipelines help shepherd changes through automated testing cycles, out to staging environments, and finally to production.</p><p>The more comprehensive your testing pipelines are, the greater assurance you have that changes won’t introduce unforeseen side effects into your production deployment.</p><p>Let’s take a look at how lighty.io achieves high-performance integration testing.</p><p><span style="text-decoration: underline;">lighty.io components used in this test are:</span></p><ol><li>lighty.io based SDN controller. RESTCONF on the northbound interface, NETCONF on the southbound interface.</li><li>lighty.io NETCONF toaster device simulator (Toaster device simulator is based on lighty.io NETCONF device library and internally uses the famous toaster model)</li><li>lighty.io NETCONF topology device simulator. (Network device simulator is based on lighty.io NETCONF device library and internally uses network-topology model)</li><li>lighty.io RESTCONF java client.</li></ol><p><strong>Test Architecture</strong></p><p>As you can see, this integration test can start all 3 layers in a single JVM instance. This is possible because lighty.io provides not only components for the SDN controller (layer 2), but also RESTCONF client (layer 1) and NETCONF device simulators (layer 3). YANG models are shared between all layers to achieve data type safety. In fact, this test will start a small test network and exercise all layers involved using different ports on the localhost.</p><p><img decoding="async" src="https://testsite.lighty.io/wp-content/uploads/2018/05/test-architecture-300x215.png" alt="" class="wp-image-683 alignnone" srcset="https://testsite.lighty.io/wp-content/uploads/2018/05/test-architecture-300x215.png 300w, https://testsite.lighty.io/wp-content/uploads/2018/05/test-architecture.png 719w" sizes="(max-width: 618px) 100vw, 618px" width="618" height="443" /></p><p><strong>The mission of this test exercise will be</strong></p><ol><li>to start the SDN controller.</li><li>start the first NETCONF test device (Toaster).</li><li>start the second NETCONF test device (Topology Device).</li><li>connect both devices to the SDN controller.</li><li>connect java RESTCONF client to SDN controller.</li><li>get data from device models, listen for device notifications, call RPCs on devices.</li><li>evaluate test data.</li><li>shutdown this test setup.</li></ol><h3><strong>JUnit test design</strong></h3><p>As all components involved in this test are written in java, we can start complete network simulation in a single unit test.</p><p>The advantage is, that the unit test logic has access to the internal APIs of all 3 layers. This means quite complex tests are very easy to perform. In fact, this test does not require any mocked components. All components involved are used in real deployment as well.</p><h4><strong>JUnit test initialization</strong></h4><ul><li>Initializes test network consisting of the SDN controller and two NETCONF test devices.</li><li>Waits until all components are up and running.</li><li>Connect REST client to SDN controller using RESTCONF and HTTP2.</li><li>Connect Toaster and Topology device to SDN controller.</li><li><em>Duration ~10s</em></li></ul><h4><strong>JUnit test execution</strong></h4><ul><li><em>testRestClientCreateSubscriptionAll duration: ~0.3s</em><br />This is the RESTCONF notification test. The test subscribes to a notification on the Topology NETCONF device and triggers them via an RPC call.<br /><div id="attachment_681" class="wp-caption alignnone"><div id="attachment_681" style="width: 511px" class="wp-caption alignnone"><img loading="lazy" decoding="async" aria-describedby="caption-attachment-681" src="https://testsite.lighty.io/wp-content/uploads/2018/05/notification-sequence-275x300.png" alt="" class="wp-image-681" srcset="https://testsite.lighty.io/wp-content/uploads/2018/05/notification-sequence-275x300.png 275w, https://testsite.lighty.io/wp-content/uploads/2018/05/notification-sequence.png 652w" sizes="(max-width: 501px) 100vw, 501px" width="501" height="547" /><p id="caption-attachment-681" class="wp-caption-text">Sequence diagram of testRestClientCreateSubscriptionAll</p></div></div></li><li><em>testToasterReadDeleteDatastoreOperations: ~0.1s</em><br />This test uses datastore operation of Toaster device in order to read and delete<br /><div id="attachment_684" class="wp-caption alignnone"><div id="attachment_684" style="width: 516px" class="wp-caption alignnone"><img loading="lazy" decoding="async" aria-describedby="caption-attachment-684" src="https://testsite.lighty.io/wp-content/uploads/2018/05/toaster-datastore-operations-sequence-275x300.png" alt="" class="wp-image-684" srcset="https://testsite.lighty.io/wp-content/uploads/2018/05/toaster-datastore-operations-sequence-275x300.png 275w, https://testsite.lighty.io/wp-content/uploads/2018/05/toaster-datastore-operations-sequence.png 652w" sizes="(max-width: 506px) 100vw, 506px" width="506" height="552" /><p id="caption-attachment-684" class="wp-caption-text">Sequence diagram of testToasterReadDeleteDatastoreOperations</p></div></div></li><li><em>testTopologyDeviceRPCInputOutput: ~0.6s</em><br />This test calls RPCs on topology device.<br /><div id="attachment_682" class="wp-caption alignnone"><div id="attachment_682" style="width: 511px" class="wp-caption alignnone"><img loading="lazy" decoding="async" aria-describedby="caption-attachment-682" src="https://testsite.lighty.io/wp-content/uploads/2018/05/rpc-sequence-275x300.png" alt="" class="wp-image-682" srcset="https://testsite.lighty.io/wp-content/uploads/2018/05/rpc-sequence-275x300.png 275w, https://testsite.lighty.io/wp-content/uploads/2018/05/rpc-sequence.png 652w" sizes="(max-width: 501px) 100vw, 501px" width="501" height="547" /><p id="caption-attachment-682" class="wp-caption-text">Sequence diagram of testTopologyDeviceRPCInputOutput</p></div></div></li></ul><h4><strong>JUnit test shutdown</strong></h4><p>Stop all components and wait until stopped.</p><ul><li><em>Duration: ~0.08s</em><br />Total test run: ~12s<br />Hardware configuration: Intel i7-4810MQ CPU, 16GB DDR3 RAM, JDK 8, Ubuntu 18.04 LTS</li></ul><p>Links to project source code:</p><ul><li> <a href="https://lighty.io/netconfrestconfittest/" target="_blank" rel="noopener noreferrer">Full JUnit test source</a></li><li> <a href="https://lighty.io/pom/" target="_blank" rel="noopener noreferrer">Full pom.xml dependencies</a></li></ul><p>Speed and flexibility matter. Lighty.io offers a set of components to achieve record-breaking speeds in integration testing and continuous integration. A</p><p>fter moving from upstream OpenDaylight to lighty.io, <strong>our projects are compiled and tested in seconds or minutes, rather than hours</strong>. How fast can your test system go from starting a small test network to running tests and full stop?</p><p>If you are interested, please register <a href="http://lighty.io/#contact">here</a> for regular updates, <strong>click on the Contact Us button on the menu of this page.</strong></p><p>Juraj Veverka</p></article>								</div>
				</div>
					</div>
		</div>
					</div>
		</section>
				</div>
		<p>The post <a href="https://lighty.io/netconf-performance-test/">Rapid NETCONF Controller Integration Testing</a> appeared first on <a href="https://lighty.io">lighty.io</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>ONAP SDN-C</title>
		<link>https://lighty.io/onap-sdnc-on-lighty-io-use-case/</link>
		
		<dc:creator><![CDATA[lighty.io]]></dc:creator>
		<pubDate>Thu, 29 Mar 2018 09:42:38 +0000</pubDate>
				<category><![CDATA[lighty.io]]></category>
		<category><![CDATA[Post]]></category>
		<guid isPermaLink="false">https://lighty.io/?p=702</guid>

					<description><![CDATA[<p>In the contemporary SDN world, ONAP (Open Network Automation Platform) is quite a trend. ONAP is a big project composed of a number of sub-projects (or components if you like), which together form a platform for orchestration and automation of network functions. There are big companies involved in ONAP and<a class="moretag" href="https://lighty.io/onap-sdnc-on-lighty-io-use-case/"> Read more</a></p>
<p>The post <a href="https://lighty.io/onap-sdnc-on-lighty-io-use-case/">ONAP SDN-C</a> appeared first on <a href="https://lighty.io">lighty.io</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p style="text-align: justify;">In the contemporary SDN world, <strong>ONAP</strong> (Open Network Automation Platform) is quite a trend. ONAP is a big project composed of a number of sub-projects (or components if you like), which together form a platform for orchestration and automation of network functions. There are big companies involved in ONAP and its development is speeding up rapidly.</p>
<p><iframe title="ONAP SDN-C on lighty.io | PANTHEON.tech" width="750" height="422" src="https://www.youtube.com/embed/GJzKwoc_LVI?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe></p>
<p>SDN-C is one of many ONAP’s components, which is essentially OpenDaylight with <a href="https://wiki.onap.org/display/DW/Service+Logic+Interpreter+Directed+Graph+Guide">added functionality for the execution of directed graphs.</a></p>
<h2>SDN-C deployment architecture</h2>
<p>ONAP SDN-C deployment is composed of several Docker containers. One of these containers runs Directed Graph Builder. It’s a web UI you can use to build directed graphs in a user-friendly manner.</p>
<p>Another container runs Admin Portal, which is another web UI for SDNC.</p>
<p>The next one runs the relational database, which is the central point of SNDC deployment and each container is using it.</p>
<p>Finally, there is a container that runs the SDNC controller itself. This is the one we are in particular interested in because it has all the logic behind the execution of directed graphs.</p>
<p style="text-align: justify;">We found out that the SDNC container takes more than 300 seconds to initialize and it consumes 1,125 GiB of RAM after initialization. We were thinking &#8211; could we do something to make it more efficient?  lighty.io comes to the rescue!</p>
<h2>Migration of SDNC to lighty.io</h2>
<p style="text-align: justify;">As we already mentioned, SDNC is based on Opendaylight and what we wanted to achieve is make it more efficient and more suitable for microservice deployments. This is exactly the use case for lighty.io. We decided to migrate SDNC from Opendaylight to lighty.io and build our own Docker image for it.</p>
<p>We cover some of the technical aspects behind this migration in a separate article, here we will only summarize our achievements:</p>
<ul>
<li>Ability to execute directed graphs (you can see it in action in our video)</li>
<li>Less memory usage</li>
<li>Quicker startup time</li>
</ul>
<p>Here is a simple table with a comparison of our Pantheon lighty.io SDNC container with vanilla SDNC container:</p>
<table width="0">
<tbody>
<tr>
<td width="276"></td>
<td width="189"><strong>Vanilla SDN-C container</strong></td>
<td width="200"><strong>lighty.io SDN-C container</strong></td>
</tr>
<tr>
<td width="276"><strong>Initialization time[1]</strong></td>
<td width="189">388 s</td>
<td width="200">147 s</td>
</tr>
<tr>
<td width="276"><strong>Memory usage after startup</strong></td>
<td width="189">1,125 GiB</td>
<td width="200">613,1 MiB</td>
</tr>
<tr>
<td width="276"><strong>Memory usage after test graph[2] execution</strong></td>
<td width="189">1,246 GiB</td>
<td width="200">937 MiB</td>
</tr>
<tr>
<td width="276"><strong>Average execution time of test graph</strong></td>
<td width="189">1,49 s</td>
<td width="200">1,2 s</td>
</tr>
<tr>
<td width="276"><strong>Average cpu[3] usage during test graph execution</strong></td>
<td width="189">115,27 %</td>
<td width="200">108,06 %</td>
</tr>
</tbody>
</table>
<p>[1]The execution time of init script running in containers</p>
<p>[2]The graph used for testing reads data from MD-SAL and writes them to log 1000 times in a loop.</p>
<p>[3]Containers have available 4 CPU cores</p>
<h2>Summary<o:p></o:p></h2>
<p>Thanks to the migration exercise we proved that even a quite complex application can be migrated to lighty.io in a short time and achieve measurable improvements. <a href="https://lighty.io/migration-of-onap-sdnc-to-lighty-io/" target="_blank" rel="noopener noreferrer">Click here to read more about the migration process!</a></p>
<p>If you are interested in further SDN/C performance and architecture optimizations, <a href="https://lighty.io/contact/">contact us!</a><o:p></o:p></p>
<p>The post <a href="https://lighty.io/onap-sdnc-on-lighty-io-use-case/">ONAP SDN-C</a> appeared first on <a href="https://lighty.io">lighty.io</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>OpenFlow Support in lighty.io</title>
		<link>https://lighty.io/openflow-in-lighty-io/</link>
		
		<dc:creator><![CDATA[lighty.io]]></dc:creator>
		<pubDate>Thu, 29 Mar 2018 06:48:36 +0000</pubDate>
				<category><![CDATA[lighty.io]]></category>
		<category><![CDATA[Post]]></category>
		<guid isPermaLink="false">https://lighty.io/?p=655</guid>

					<description><![CDATA[<p>OpenFlow enables network controllers to determine the path of network packets across a network of switches. Controllers are different from switches. Separation of control from the forwarding allows for more sophisticated traffic management than is feasible using access control lists (ACLs) and routing protocols. Also, OpenFlow allows switches from different<a class="moretag" href="https://lighty.io/openflow-in-lighty-io/"> Read more</a></p>
<p>The post <a href="https://lighty.io/openflow-in-lighty-io/">OpenFlow Support in lighty.io</a> appeared first on <a href="https://lighty.io">lighty.io</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>OpenFlow enables network controllers to determine the path of network packets across a network of switches.</p>
<p>Controllers are different from switches. Separation of control from the forwarding allows for more sophisticated traffic management than is feasible using access control lists (ACLs) and routing protocols.</p>
<p>Also, OpenFlow allows switches from different vendors — often each with their own proprietary interfaces and scripting languages — to be managed remotely using a single, open protocol. The protocol&#8217;s inventors consider OpenFlow an enabler of software-defined networking (SDN).</p>
<p><iframe title="OpenFlow plugin on lighty.io | PANTHEON.tech" width="750" height="422" src="https://www.youtube.com/embed/aTPcXzsadtg?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe></p>
<p>OpenFlow allows remote administration of a layer 3 switch&#8217;s packet forwarding tables, by adding, modifying, and removing packet matching rules and actions.</p>
<p>With this solution, you can make routing decisions periodically or ad hoc by the controller after which they can be translated into rules and actions with a configurable lifespan.</p>
<h3>OpenFlow Capabilities</h3>
<p>Later on, they can be deployed to a switch&#8217;s flow table, leaving the actual forwarding of matched packets to the switch at wire speed for the duration of those rules. Packets that are unmatched by the switch can be forwarded to the controller.</p>
<p>The controller can then decide to modify existing flow table rules on one or more switches or to deploy new rules, to prevent a structural flow of traffic between switch and controller.</p>
<p>It could even decide to forward the traffic itself, provided that it has told the switch to forward entire packets instead of just their header.</p>
<p>The OpenFlow protocol is layered on top of the Transmission Control Protocol (TCP) and prescribes the use of Transport Layer Security (TLS). Controllers should listen on TCP port 6653 for switches that want to set up a connection. Earlier versions of the OpenFlow protocol unofficially used port 6633.</p>
<p>Openflow usage in OpenDaylight is based on the <a href="https://docs.opendaylight.org/en/stable-neon/user-guide/openflow-plugin-project-user-guide.html">OpenFlow plugin project</a>. In order to connect OpenFlow devices to the lighty.io controller, we had to migrate the OpenFlow plugin project.</p>
<p>The Openflow project and its parts are initialized using blueprints in vanilla OpenDaylight, so to get the project up in lighty.io we have to initialize these explicitly. In addition, the OpenFlow plugin has a direct link to the Karaf bundle context and so we have to re-implement the OpenFlow plugin configuration part.</p>
<p>Although this sounds like a lot of work, it is still very straightforward.</p>
<h3>Openflowplugin detail architecture</h3>
<p><img loading="lazy" decoding="async" width="706" height="689" src="https://lighty.io/wp-content/uploads/2018/03/Topology-Manager.png" alt="" srcset="https://lighty.io/wp-content/uploads/2018/03/Topology-Manager.png 706w, https://lighty.io/wp-content/uploads/2018/03/Topology-Manager-300x293.png 300w" sizes="(max-width: 706px) 100vw, 706px"></p>
<h3>Blueprints in OpenFlow plugin</h3>
<pre data-enlighter-language="python">    &lt;reference id="defaultSwitchConnProvider" interface="org.opendaylight.openflowjava.protocol.spi.connection.SwitchConnectionProvider"
               odl:type="openflow-switch-connection-provider-default-impl"/&gt;
    &lt;reference id="legacySwitchConnProvider" interface="org.opendaylight.openflowjava.protocol.spi.connection.SwitchConnectionProvider"
               odl:type="openflow-switch-connection-provider-legacy-impl"/&gt;
    &lt;reference id="openflowPluginProviderFactory"
               interface="org.opendaylight.openflowplugin.api.openflow.OpenFlowPluginProviderFactory"/&gt;
    &lt;reference id="configurationServiceFactory"
               interface="org.opendaylight.openflowplugin.api.openflow.configuration.ConfigurationServiceFactory"/&gt;
    &lt;reference id="mastershipChangeServiceManager"
               interface="org.opendaylight.openflowplugin.api.openflow.mastership.MastershipChangeServiceManager"/&gt;
    &lt;odl:clustered-app-config id="openflowProviderConfig"
                              binding-class="org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.openflow.provider.config.rev160510.OpenflowProviderConfig"/&gt;
    &lt;bean id="configurationService"
          factory-ref="configurationServiceFactory"
          factory-method="newInstance"
          destroy-method="close"&gt;
        &lt;argument ref="openflowProviderConfig" /&gt;
        &lt;argument ref="blueprintBundleContext" /&gt;
        &lt;cm:managed-properties persistent-id="org.opendaylight.openflowplugin"
                               update-strategy="component-managed"
                               update-method="update"/&gt;
    &lt;/bean&gt;
    &lt;service ref="configurationService" interface="org.opendaylight.openflowplugin.api.openflow.configuration.ConfigurationService"/&gt;
    &lt;bean id="openflowPluginProvider"
          factory-ref="openflowPluginProviderFactory"
          factory-method="newInstance"
          destroy-method="close"&gt;
        &lt;argument ref="configurationService"/&gt;
        &lt;argument ref="dataBroker"/&gt;
        &lt;argument ref="rpcRegistry"/&gt;
        &lt;argument ref="notificationPublishService"/&gt;
        &lt;argument ref="entityOwnershipService"/&gt;
        &lt;argument&gt;
            &lt;list&gt;
                &lt;ref component-id="defaultSwitchConnProvider"/&gt;
                &lt;ref component-id="legacySwitchConnProvider"/&gt;
           &lt;/list&gt;
        &lt;/argument&gt;
        &lt;argument ref="clusterSingletonServiceProvider"/&gt;
        &lt;argument ref="mastershipChangeServiceManager"/&gt;
    &lt;/bean&gt;
    &lt;service ref="openflowPluginProvider" odl:type="openflow-plugin-provider-impl"&gt;
        <interfaces>
            <value>org.opendaylight.openflowplugin.api.openflow.OpenFlowPluginProvider</value>
            <value>org.opendaylight.openflowplugin.extension.api.OpenFlowPluginExtensionRegistratorProvider</value>
        </interfaces>
    &lt;/service&gt;
&lt;/blueprint&gt;
</pre>
<p>As you can see, the OpenFlow plugin uses OpenDaylight Controller dependencies and classes, like Entityownership, ClusterSingletonService, DataBroker, and NotificationService.</p>
<p>The Open Daylight Controller supports the OpenFlow protocol. The Controller architecture supports both the Hybrid Switch model as well as the classic OpenFlow model of having a fully centralized Control Plane. Service using bundle context</p>
<pre data-enlighter-language="python">/**
 * Factory for creating ConfigurationService instances.
 */
public interface ConfigurationServiceFactory {
    ConfigurationService newInstance(OpenflowProviderConfig providerConfig,
                                     BundleContext bundleContext);
}
</pre>
<p>The OpenDaylight OpenFlow plugin implementation of this interface is using the Karaf bundle context, which we don’t have in lighty.io. Therefore, we need to re-implement it in lighty.io.</p>
<h3>Configuration of OpenFlow plugin w/ lighty.io</h3>
<p>OpenFlow plugin uses a separate configuration for each plugin configuration and separate configuration for switch connectors. In this lighty.io example use case we’ve put it together and here you can see an example JSON file to configure OpenFlow plugin.</p>
<pre data-enlighter-language="python">{
  "openflow": {
    "isStatisticsPollingOn": true,
    "barrierCountLimit": "1234",
    "barrierIntervalTimeoutLimit": "3000",
    "basicTimerDelay": "2690",
    "echoReplyTimeout": "4000",
    "globalNotificationQuota": "9000",
    "maximumTimerDelay": "3679",
    "rpcRequestsQuota": "2500",
    "threadPoolMaxThreads": "1000",
    "threadPoolMinThreads": "3",
    "threadPoolTimeout": "60",
    "enableFlowRemovedNotification": "true",
    "isStatisticsRpcEnabled": "false",
    "skipTableFeatures": "true",
    "switchFeaturesMandatory": "false",
    "useSingleLayerSerialization": "true",
    "switchConfig": {
      "instanceName":"openflow-switch-connection-provider-default-impl",
      "port":1234,
      "transportProtocol":0,
      "useBarrier":true,
      "switchIdleTimeout":15001,
      "keystore":"configuration/ssl/ctl.jks",
      "keystoreType":0,
      "keystorePathType":1,
      "keystorePassword":"opendaylight",
      "truststore":"configuration/ssl/truststore.jks",
      "truststoreType":0,
      "truststorePathType":1,
      "truststorePassword":"opendaylight",
      "certificatePassword":"opendaylight"
    }
  }
}
</pre>
<h3>Openflowplugin example application in lighty.io</h3>
<p>We managed to create an example application using lighty.io. It might be a helping hand to those who wish to use OpenFlow their lighty.io controllers.</p>
<p>The structure of the example is the same as in the other examples: start the necessary dependencies such as Controller or Restconf. We need Restconf in this example only to be able to manage the resulting controller using operations like a post or to get flow and device information.</p>
<p>Program core structure:</p>
<pre data-enlighter-language="python">//1. initialize and start Lighty controller (MD-SAL, Controller, YangTools, Akka)
final LightyControllerBuilder lightyControllerBuilder = new LightyControllerBuilder();
final LightyController lightyController = lightyControllerBuilder.from(controllerConfiguration).build();
lightyController.start().get();
//2. start Restconf server
final RestconfBuilder restconfBuilder = new RestconfBuilder();
final LightyModule restconf = restconfBuilder.from(RestconfConfigUtil
        .getRestConfConfiguration(restConfConfiguration, lightyController.getServices()))
        .build();
restconf.start();
//3. start openflow SBP
final OpenflowSouthboundPlugin plugin;
plugin = new OpenflowSouthboundPluginBuilder()
        .from(configuration, lightyController.getServices())
        .build();
plugin.start();
</pre>
<h3>Controller start and device connection</h3>
<p>After a build of a lighty-restconf-ofp-app in lighty.io, you can unzip the created file into a separate folder and run the controller with start script.</p>
<pre data-enlighter-language="python">INFO [main] (Main.java:100) - Lighty and OFP started in 7649.765ms
</pre>
<p>The above logline tells us, that the controller and OpenFlow plugin are running. Now we can join an OpenFlow device using Mininet.</p>
<pre data-enlighter-language="python">sudo mn --controller=remote,ip=127.0.0.1 --topo=tree,1 --switch ovsk,protocols=OpenFlow13
</pre>
<p>We can see in the log above, that the device <em>openflow:1</em> is connected and mastered by the controller.</p>
<pre data-enlighter-language="python">INFO [nioEventLoopGroup-10-2] (ContextChainHolderImpl.java:225) - Role MASTER was granted to device openflow:1
</pre>
<h3>Post Flow / Check Device in the operational datastore</h3>
<p>The last thing is to set a flow on the connected device (opeflow:1) and check if it is properly installed.</p>
<p>POST this flow:</p>
<pre data-enlighter-language="python">curl -X POST -k -H 'Content-Type: application/xml' -H 'Authorization: Basic YWRtaW46YWRtaW4=' -i https://localhost:8888/restconf/operations/sal-flow:add-flow --data '<!--?xml version="1.0" encoding="UTF-8" standalone="no"?-->
<input xmlns="urn:opendaylight:flow:service" type="text">
   <barrier>false</barrier>
   <node xmlns:inv="urn:opendaylight:inventory">/inv:nodes/inv:node[inv:id="openflow:1"]</node>
   <cookie>55</cookie>
   <flags>SEND_FLOW_REM</flags>
   <hard-timeout>0</hard-timeout>
   <idle-timeout>0</idle-timeout>
   <installhw>false</installhw>
   <match>
    <ethernet-match>
     <ethernet-type>
       <type>2048</type>
     </ethernet-type>
    </ethernet-match>
    <ipv4-destination>10.0.10.2/32</ipv4-destination>
   </match>
	<instructions>
		<instruction>
			<order>0</order>
			<apply-actions><action>
				<order>0</order>
				<output-action>
					<output-node-connector>INPORT</output-node-connector>
				</output-action>
				</action>
			</apply-actions>
		</instruction>
	</instructions>
	<priority>0</priority>
   <strict>false</strict>
   <table_id>0</table_id>
&lt;/input&gt;
</pre>
<p>And check the device:</p>
<pre data-enlighter-language="python">curl -X GET -k -H 'Authorization: Basic YWRtaW46YWRtaW4=' -i 'https://localhost:8888/restconf/data/opendaylight-inventory:nodes/node=openflow%3A1/table=0?content=nonconfig'
</pre>
<p>After all this, you have to create proof that the device is connected with the newly created lighty.io controller using the OpenDaylight OpenFlow plugin.</p>
<pre data-enlighter-language="python">{
  "flow-node-inventory:table": [{
    "id": 0,
    "flow": [{
      "id": "#UF$TABLE*0-1",
      "cookie_mask": 0,
      "priority": 0,
      "table_id": 0,
      "opendaylight-flow-statistics:flow-statistics": {
        "duration": {
          "second": 20,
          "nanosecond": 196000000
        },
        "byte-count": 0,
        "packet-count": 0
      },
      "match": {
        "ipv4-destination": "10.0.10.2/32",
        "ethernet-match": {
          "ethernet-type": {
            "type": 2048
          }
        }
      },
      "flags": "SEND_FLOW_REM",
      "idle-timeout": 0,
      "hard-timeout": 0,
      "cookie": 55,
      "instructions": {
        "instruction": [{
          "order": 0,
          "apply-actions": {
            "action": [{
              "order": 0,
              "output-action": {
                "output-node-connector": "IN_PORT",
                "max-length": 0
              }
            }]
          }
        }]
      }
    }]
  }]
}
</pre>


<p>Congratulations! You have successfully experimented with the OpenFlow plugin in lighty.io!</p>
<p>The post <a href="https://lighty.io/openflow-in-lighty-io/">OpenFlow Support in lighty.io</a> appeared first on <a href="https://lighty.io">lighty.io</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Migration of TransportPCE to lighty.io</title>
		<link>https://lighty.io/migration-of-odl-transportpce-to-lighty-io/</link>
		
		<dc:creator><![CDATA[lighty.io]]></dc:creator>
		<pubDate>Wed, 28 Mar 2018 09:42:41 +0000</pubDate>
				<category><![CDATA[lighty.io]]></category>
		<category><![CDATA[Post]]></category>
		<guid isPermaLink="false">https://lighty.io/?p=616</guid>

					<description><![CDATA[<p>Update 13/8/2019: lighty TransportPCE Controller&#160;is now available in the&#160;OpenDaylight upstream! The migration of an OpenDaylight application to lighty.io is simple and straightforward. In this post, we are going to show you how to do this with help of the TransportPCE OpenDaylight project acting as an example. Users can find many<a class="moretag" href="https://lighty.io/migration-of-odl-transportpce-to-lighty-io/"> Read more</a></p>
<p>The post <a href="https://lighty.io/migration-of-odl-transportpce-to-lighty-io/">Migration of TransportPCE to lighty.io</a> appeared first on <a href="https://lighty.io">lighty.io</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>Update 13/8/2019:<b> <a href="https://git.opendaylight.org/gerrit/gitweb?p=transportpce.git;a=tree;f=lighty" target="_blank" rel="noopener noreferrer">lighty TransportPCE Controller</a>&nbsp;is now available in the&nbsp;<a href="http://bit.ly/lightytpce" target="_blank" style="background-color: #ffffff;" rel="noopener noreferrer">OpenDaylight upstream!</a></b></p>
<p style="text-align: justify;">The migration of an OpenDaylight application to lighty.io is simple and straightforward. In this post, we are going to show you how to do this with help of the TransportPCE OpenDaylight project acting as an example.</p>
<p style="text-align: justify;">Users can find many examples shipped along with the lighty.io package to help them jumpstart projects, but this post will detail the migration process in particular.</p>
<p><iframe title="Migration of OpenDaylight TransportPCE to lighty.io | PANTHEON.tech" width="750" height="422" src="https://www.youtube.com/embed/r11AMRumcMY?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe></p>
<p>The major part of the migration is <strong>removing hard dependencies in OSGi / Karaf.</strong></p>
<p style="text-align: justify;">This exercise is good for the OpenDaylight project itself, as these dependencies should not exist in the first place. We recommend sending the resulting patch to the upstream track as a step towards cleaner code.</p>
<p style="text-align: justify;">Since there are no OSGI dependencies in the TransportPCE project, we will focus on the rest of the work that needs to be done. To begin, you need to find out what other OpenDaylight modules (e.g. controller, NETCONF, RESTCONF) the given project uses (depends on).</p>
<p style="text-align: justify;"><strong>TransportPCE’s dependencies are already migrated to lighty.io</strong> and therefore it is as easy as initialization of an object and calling a start function.</p>
<p><span style="text-decoration: underline;">Initializing object and calling a start function:</span></p>
<pre data-enlighter-language="python">        //1. initialize and start OpenDaylight controller (MD-SAL, Controller, YangTools, Akka)
        final LightyControllerBuilder lightyControllerBuilder = new LightyControllerBuilder();
        final LightyController lightyController = lightyControllerBuilder.from(controllerConfiguration).build();
        lightyController.start().get();
</pre>
<p>The second step is to build the lighty.io TransportPCE object. To do this you have to go to the original project and find all the blueprint files.</p>
<p>These will specify the dependency references that are needed by your newly created object constructor and beans, which are the objects that you will create using those references.</p>
<p>These beans also have names of functions that you need for initializing and destroying of the object blueprint example:</p>
<pre data-enlighter-language="python">&lt;blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
  xmlns:odl="http://opendaylight.org/xmlns/blueprint/v1.0.0"
  odl:use-default-for-reference-types="true"&gt;
  &lt;reference id="dataBroker"
    interface="org.opendaylight.controller.md.sal.binding.api.DataBroker"
    odl:type="default" /&gt;
  &lt;reference id="mountPointService"
    interface="org.opendaylight.controller.md.sal.binding.api.MountPointService" /&gt;
  &lt;reference id="rpcProviderRegistry"
    interface="org.opendaylight.controller.sal.binding.api.RpcProviderRegistry" /&gt;
  &lt;bean id="provider"
    init-method="init" destroy-method="close"&gt;
    &lt;argument ref="dataBroker" /&gt;
    &lt;argument ref="mountPointService" /&gt;
    &lt;argument ref="rpcProviderRegistry" /&gt;
  &lt;/bean&gt;
&lt;/blueprint&gt;
</pre>
<p style="text-align: justify;">The next step is to initialize all the objects that TransportPCE needs to function. lighty.io has an abstract helper class called <em>AbstractLightyModule</em> which you should extend.</p>
<p style="text-align: justify;">With this, you will be overriding an <em>initProcedure</em> function and whenever you call <em>start</em> on your lighty.io object, this function will be triggered. In this function, all you need to do is to create all the beans from blueprints and call their initializing function.</p>
<p><span style="text-decoration: underline;">Start method from abstract class:</span></p>
<pre data-enlighter-language="python">public synchronized ListenableFuture&lt;Boolean&gt; start() {
        if(this.running) {
            LOG.warn("LightyModule {} is already started.", this.getClass().getSimpleName());
            return Futures.immediateFuture(Boolean.valueOf(true));
        } else {
            if(this.executorService == null) {
                LOG.debug("Creating default single thread ExecutorService for LightyModule {}.", this.getClass().getSimpleName());
                this.executorService = MoreExecutors.listeningDecorator(Executors.newSingleThreadExecutor());
            }
            LOG.info("Submitted start of LightyModule {}.", this.getClass().getSimpleName());
            return this.executorService.submit(() -&gt; {
                synchronized(this) {
                    LOG.debug("Starting initialization of LightyModule {}", this.getClass().getSimpleName());
                    boolean initResult = this.initProcedure();
                    this.running = true;
                    LOG.info("LightyModule {} started.", this.getClass().getSimpleName());
                    return Boolean.valueOf(initResult);
                }
            });
        }
    }
</pre>
<p><span style="text-decoration: underline;">Initializing and calling start on lightyTransportPce object:</span></p>
<pre data-enlighter-language="python">        //start TransportPce application
        final LightyTransportPce lightyTransportPce;
        final TransportPceBuilder lightyTransportPceBuilder = new TransportPceBuilder();
        lightyTransportPce = lightyTransportPceBuilder.from(lightyController.getServices()).build();
        lightyTransportPce.start().get();
overriding a initProcedure method:
    @Override
    protected boolean initProcedure() {
        final long startTime = System.nanoTime();
        LOG.info("Starting TransportPceProvider");
        transportpceProvider =
                new TransportpceProvider(dataBroker, mountPointService);
        transportpceProvider.init();
        LOG.info("Starting RendererProvider");
        rendererProvider = new RendererProvider(dataBroker, mountPointService,
                rpcProviderRegistry);
        rendererProvider.init();
        LOG.info("Starting OlmProvider");
        olmProvider = new OlmProvider(dataBroker, mountPointService, rpcProviderRegistry);
        olmProvider.init();
        LOG.info("Starting StubrendererProvider");
        stubrendererProvider = new StubrendererProvider(rpcProviderRegistry,
                notificationService,notificationPublishService);
        stubrendererProvider.init();
        LOG.info("Starting StubpceProvider");
        stubpceProvider = new StubpceProvider(rpcProviderRegistry, notificationService,
                notificationPublishService);
        stubpceProvider.init();
        LOG.info("Starting ServiceHandlerProvider");
        servicehandlerProvider = new ServicehandlerProvider(dataBroker, rpcProviderRegistry,
                notificationService, notificationPublishService);
        servicehandlerProvider.init();
        final float delay = (System.nanoTime() - startTime) / 1_000_000f;
        LOG.info("Lighty transportpce started in {}ms", delay);
        return true;
    }
</pre>
<p style="text-align: justify;">The last step is to override the <em>stopProcedure</em> function. This function needs to call the destroy method of an object that you created. Whenever <em>shutdown</em>&nbsp;is called on a lighty.io object, this method will be triggered.</p>
<p><span style="text-decoration: underline;">Override a stopProcedure method:</span></p>
<pre data-enlighter-language="python">@Override
    protected boolean stopProcedure() {
        if (transportpceProvider != null) {
            transportpceProvider.close();
            LOG.info("TransportpceProvider closed");
        }
        if (olmProvider != null) {
            olmProvider.close();
            LOG.info("OlmProvider closed");
        }
        if (rendererProvider != null) {
            rendererProvider.close();
            LOG.info("RendererProvider stopped");
        }
        if (rendererProvider != null) {
            rendererProvider.close();
            LOG.info("RendererProvider stopped");
        }
        if (servicehandlerProvider != null) {
            servicehandlerProvider.close();
            LOG.info("ServicehandlerProvider stopped");
        }
        if (stubpceProvider != null) {
            stubpceProvider.close();
            LOG.info("StubpceProvider stopped");
        }
        if (stubrendererProvider != null) {
            stubrendererProvider.close();
            LOG.info("StubrendererProvider stopped");
        }
        return true;
    }
Shutdown method from abstract class
    public synchronized ListenableFuture&lt;Boolean&gt; shutdown() {
        if(!this.running) {
            LOG.warn("LightyModule {} is already shut down.", this.getClass().getSimpleName());
            return Futures.immediateFuture(Boolean.valueOf(true));
        } else {
            LOG.info("Submitted shutdown of LightyModule {}.", this.getClass().getSimpleName());
            ListenableFuture&lt;Boolean&gt; shutdownFuture = this.executorService.submit(() -&gt; {
                synchronized(this) {
                    LOG.debug("Starting shutdown procedure of LightyModule {}.", this.getClass().getSimpleName());
                    boolean stopResult = this.stopProcedure();
                    this.shutdownLatch.countDown();
                    this.running = false;
                    LOG.info("LightyModule {} shutdown complete.", this.getClass().getSimpleName());
                    return Boolean.valueOf(stopResult);
                }
            });
            return !this.executorIsProvided?Futures.transform(shutdownFuture, (result) -&gt; {
                LOG.debug("Shutdown default ExecutorService of LightyModule {}.", this.getClass().getSimpleName());
                this.executorService.shutdown();
                this.executorService = null;
                return Boolean.valueOf(true);
            }, MoreExecutors.directExecutor()):shutdownFuture;
        }
    }
</pre>
<p style="text-align: justify;">Keep in mind, that your controller has to have access to all YANG model artifacts that you are using in your project. If you fail to do so, the schema context of the controller will be missing them and therefore some of your bean objects will not work properly.</p>
<p style="text-align: justify;">As you can see, <strong>these steps are simple and straightforward.</strong> If all the OpenDaylight projects were this clean, a simple script would be able to take care of migration from OpenDaylight to lighty.io.</p>
<p>The post <a href="https://lighty.io/migration-of-odl-transportpce-to-lighty-io/">Migration of TransportPCE to lighty.io</a> appeared first on <a href="https://lighty.io">lighty.io</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>HTTP Server w/ YANG Modeled RPC in Java</title>
		<link>https://lighty.io/how-to-build-http-server-implementing-yang-modelled-rpc-in-java/</link>
		
		<dc:creator><![CDATA[lighty.io]]></dc:creator>
		<pubDate>Wed, 28 Mar 2018 08:54:21 +0000</pubDate>
				<category><![CDATA[lighty.io]]></category>
		<category><![CDATA[Post]]></category>
		<guid isPermaLink="false">https://lighty.io/?p=606</guid>

					<description><![CDATA[<p>YANG is a data modeling language, which allows modeling of Remote Procedure Calls (RPCs). YANG is widely used in networking for modeling configurational and operational data of network devices (more than just routers and switches). These devices also implement some of the well-defined protocols for transport of the data modeled<a class="moretag" href="https://lighty.io/how-to-build-http-server-implementing-yang-modelled-rpc-in-java/"> Read more</a></p>
<p>The post <a href="https://lighty.io/how-to-build-http-server-implementing-yang-modelled-rpc-in-java/">HTTP Server w/ YANG Modeled RPC in Java</a> appeared first on <a href="https://lighty.io">lighty.io</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>YANG is a data modeling language, which allows modeling of Remote Procedure Calls (RPCs).</p>
<p style="text-align: justify;">YANG is widely used in networking for modeling configurational and operational data of network devices (more than just routers and switches). These devices also implement some of the well-defined protocols for transport of the data modeled in YANG e.g.: <a href="https://tools.ietf.org/html/rfc6241">NETCONF</a>, <a href="https://tools.ietf.org/html/rfc8040">RESTCONF</a>, or <a href="http://www.openconfig.net/">GRPC</a>.</p>
<p style="text-align: justify;">Network controller software can manage such devices, by implementing these protocols and using the YANG models of the configuration and operational data.</p>
<p><iframe title="HTTP Server on lighty.io | PANTHEON.tech" width="750" height="422" src="https://www.youtube.com/embed/GMA_rnfGYAQ?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe></p>
<p style="text-align: justify;">This way, the controller or other software applications on top of the controller can configure and monitor a network of huge size. <a href="https://www.opendaylight.org/" target="_blank" rel="noopener noreferrer">OpenDaylight</a> is the leading open source SDN controller, which provides such functionalities.<o:p></o:p></p>
<p style="text-align: justify;">Meet <a href="https://lighty.io/download">lighty.io</a>, which is based on OpenDaylight components with additional <a href="https://pantheon.tech/contact-us/">PANTHEON.tech plugins &amp; tools</a> for fast development of lightweight SDN applications. One of the provided extensions by lighty.io is a unified API for YANG modeled data transformations.</p>
<p style="text-align: justify;">This API is important for the integration of lighty.io with external systems. This article describes how to model RPC in YANG modeling language, how to generate Java classes from the YANG model, and how to implement the modeled RPC over HTTP protocol using the Codecs component of lighty.io.</p>
<p>The YANG model of the example RPC (see the yang model file for more details) is pretty straight forward:</p>
<pre data-enlighter-language="python">    rpc compute-sum {
        input {
            leaf operand-a {
                type uint16;
                mandatory true;
            }
            leaf operand-b {
                type uint16;
                mandatory true;
            }
        }
        output {
            leaf sum {
                type uint32;
                mandatory true;
            }
        }
    }
</pre>
<p>The input of the RPC consists of two numbers and the output represents the sum of input numbers.</p>
<h3>OpenDaylight &#8211; YANG &#8211; Maven</h3>
<p style="text-align: justify;">The ODL yang-maven-plugin is used to generate Java classes and interfaces from the Yang model (see the pom.xml of this example for more details).</p>
<p style="text-align: justify;">An interface called LightyRpcExampleService is generated, which defines the RPC as a Java method with the input container as argument and output container as a return value (wrapped by Future&lt;RpcResult&lt;&gt;&gt;).</p>
<p>Now we need to provide an implementation for this freshly generated interface:</p>
<pre data-enlighter-language="python">package tech.pantheon.lighty.examples.rpc;
import org.opendaylight.yang.gen.v1.urn.pantheon.params.xml.ns.yang.lighty.rpc.example.rev180219.ComputeSumInput;
import org.opendaylight.yang.gen.v1.urn.pantheon.params.xml.ns.yang.lighty.rpc.example.rev180219.ComputeSumOutput;
import org.opendaylight.yang.gen.v1.urn.pantheon.params.xml.ns.yang.lighty.rpc.example.rev180219.ComputeSumOutputBuilder;
import org.opendaylight.yang.gen.v1.urn.pantheon.params.xml.ns.yang.lighty.rpc.example.rev180219.LightyRpcExampleService;
import org.opendaylight.yangtools.yang.common.RpcResult;
import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
import java.util.concurrent.Future;
public class LightyRpcExampleServiceImpl implements LightyRpcExampleService {
    public Future&lt;RpcResult&lt;ComputeSumOutput&gt;&gt; computeSum(ComputeSumInput input) {
        return RpcResultBuilder.success(
                new ComputeSumOutputBuilder()
                        .setSum((long) input.getOperandA() + input.getOperandB())
                        .build())
                .buildFuture();
    }
}
</pre>
<p style="text-align: justify;">The next step is to write a code, which will decode serialized input (received as HTTP payload), call the RPC, and serialize the resulting output to be sent back to the client.</p>
<p style="text-align: justify;">In the beginning, it is needed to initialize a schema context including the YANG model which is needed for serialization and deserialization of modeled data.</p>
<p style="text-align: justify;">This example shows how the schema context and RPC definition objects are initialized in the constructor of class RpcHttpServer from this example:</p>
<pre data-enlighter-language="python">        System.out.println("Loading Yang model schema context");
        /* Load YANG models available at the class path */
        List&lt;YangModuleInfo&gt; moduleInfos = new LinkedList&lt;&gt;();
        ServiceLoader&lt;YangModelBindingProvider&gt; yangProviderLoader = ServiceLoader.load(YangModelBindingProvider.class);
        for (YangModelBindingProvider yangModelBindingProvider : yangProviderLoader) {
            moduleInfos.add(yangModelBindingProvider.getModuleInfo());
        }
        /* Create the schema context for loaded models */
        ModuleInfoBackedContext moduleInfoBackedCntxt = ModuleInfoBackedContext.create();
        moduleInfoBackedCntxt.addModuleInfos(moduleInfos);
        Optional&lt;SchemaContext&gt; schemaCtx =
                moduleInfoBackedCntxt.tryToCreateSchemaContext().toJavaUtil();
        if (!schemaCtx.isPresent()) {
            throw new IllegalStateException("Failed to load schema context");
        }
        this.schemaContext = schemaCtx.get();
        System.out.println("Yang model schema context loaded");
        /* Load the RPC used in this example */
        Optional&lt;RpcDefinition&gt; loadRpc = ConverterUtils.loadRpc(schemaContext, rpcServiceQname);
        if (!loadRpc.isPresent()) {
            throw new IllegalStateException("RPC definition not found");
        }
        this.rpcDef = loadRpc.get();
        System.out.println("Loaded definition of RPC: " + this.rpcDef.getQName().getLocalName());
</pre>
<p style="text-align: justify;">The last code snippet shows how to deserialize the incoming payload of HTTP request encoded in JSON using a coded object. The method implementing RPC is called with the input object as an argument, while the output object is obtained as a return value of the method.</p>
<p style="text-align: justify;">The output object is then serialized to JSON using the same codec object as for input HTTP payload. The output JSON data can be written into HTTP response payload (see the example source code for more details).</p>
<pre data-enlighter-language="python">                /* Read the payload from HTTP request */
                final String payload = com.google.common.io.CharStreams.toString(req.getReader());
                if (payload.isEmpty()) {
                    System.out.println("Nothing received");
                    return;
                } else {
                    System.out.println("Received payload: " + payload);
                }
                /* Create codec for the RPC input and load the RPC definition */
                DataCodec&lt;ComputeSumInput&gt; dataCodec = new DataCodec&lt;&gt;(schemaContext);
                /* Deserialize the payload to normalized node */
                NormalizedNode<!--?, ?--> rpcInputNode =
                        dataCodec.withJson().deserialize(rpcDef, new StringReader(payload));
                /* Convert the normalized node to RPC's input object */
                ComputeSumInput rpcInput =
                        dataCodec.convertToBindingAwareRpc(rpcDef.getInput().getPath(),
                                                           (ContainerNode) rpcInputNode);
                /* Call the RPC and get RPC output */
                ComputeSumOutput rpcOutput =
                        rpcImpl.computeSum(rpcInput).get().getResult();
                /* Serialize the RPC output */
                Writer output = dataCodec.withJson().serializeRpc(rpcDef.getOutput(),
                                                                  dataCodec.convertToBindingIndependentRpc(rpcOutput));
                System.out.println("RPC output: " + output.toString());
</pre>
<p>You can use the following to test the RPC, and see the output:</p>
<p><em>curl -H &#8220;Content-Type: application/json&#8221; -X POST -d &#8216;{ &#8220;input&#8221;: { &#8220;operand-a&#8221;: 200, &#8220;operand-b&#8221;: 22 }}&#8217; http://localhost:8080</em></p>
<p><em>{&#8220;output&#8221;:{&#8220;sum&#8221;:222}}</em></p>
<p><strong>A sample output from the Java app above:</strong></p>
<pre data-enlighter-language="python">Loading Yang model schema context
Yang model schema context loaded
Loaded definition of RPC: compute-sum
HTTP server started at port 8080
Press any key to exit...
Received payload: { "input": { "operand-a": 200, "operand-b": 22 }}
RPC output: {"output":{"sum":222}}</pre>
<p>The post <a href="https://lighty.io/how-to-build-http-server-implementing-yang-modelled-rpc-in-java/">HTTP Server w/ YANG Modeled RPC in Java</a> appeared first on <a href="https://lighty.io">lighty.io</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>lighty.io NETCONF Device on ARM</title>
		<link>https://lighty.io/lighty-io-netconf-device-on-arm/</link>
		
		<dc:creator><![CDATA[lighty.io]]></dc:creator>
		<pubDate>Tue, 27 Mar 2018 10:43:25 +0000</pubDate>
				<category><![CDATA[lighty.io]]></category>
		<category><![CDATA[Post]]></category>
		<guid isPermaLink="false">https://lighty.io/?p=561</guid>

					<description><![CDATA[<p>lighty.io components are versatile and reusable in different scenarios. Let’s take a closer look at the lighty-netconf-device java library. This lighty.io component represents a fully programmable NETCONF communication stack, which can be integrated with hardware to achieve interoperability with lighty.io NETCONF &#8211; RESTCONF controllers. The lighty-netconf-device library implements a server<a class="moretag" href="https://lighty.io/lighty-io-netconf-device-on-arm/"> Read more</a></p>
<p>The post <a href="https://lighty.io/lighty-io-netconf-device-on-arm/">lighty.io NETCONF Device on ARM</a> appeared first on <a href="https://lighty.io">lighty.io</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p><a href="https://lighty.io/components/">lighty.io components</a> are versatile and reusable in different scenarios. Let’s take a closer look at the <strong>lighty-netconf-device java</strong> library.</p>
<p>This lighty.io component represents a fully programmable NETCONF communication stack, which can be integrated with hardware to achieve interoperability with lighty.io NETCONF &#8211; RESTCONF controllers.</p>
<p><strong>The lighty-netconf-device</strong> library implements a server for <a href="https://tools.ietf.org/html/rfc6241">RFC 6241</a> and provides related services like Datastore, RPC handling, and <a href="https://tools.ietf.org/html/rfc6241#section-7">NETCONF protocol operations</a>.</p>
<p><iframe title="lighty.io NETCONF device on ARM | PANTHEON.tech" width="750" height="422" src="https://www.youtube.com/embed/-E1Jz3unu78?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe></p>
<p style="text-align: justify;"><a href="http://raspberrypi.org">Raspberry Pi</a> is a very popular platform for hardware prototyping. <a href="https://www.raspberrypi.org/products/raspberry-pi-3-model-b/?resellerType=home">Raspberry Pi 3</a> utilizes Broadcom ARM v7 BCM2835 SoC.</p>
<p style="text-align: justify;">In this example, we will build a simple device equipped with:</p>
<ul>
<li style="text-align: justify;">4 LED state indicators</li>
<li style="text-align: justify;">4 buttons and sensors for measuring
<ul>
<li style="text-align: justify;">temperature</li>
<li style="text-align: justify;">relative humidity</li>
<li style="text-align: justify;">atmospheric pressure.</li>
</ul>
</li>
</ul>
<p>Device schematics and wiring is described on the picture below.</p>
<p><img loading="lazy" decoding="async" width="665" height="612" src="https://lighty.io/wp-content/uploads/2018/03/rpi-schematics.png" alt="" srcset="https://lighty.io/wp-content/uploads/2018/03/rpi-schematics.png 665w, https://lighty.io/wp-content/uploads/2018/03/rpi-schematics-300x276.png 300w" sizes="(max-width: 665px) 100vw, 665px"></p>
<h3><strong>Hardware components</strong></h3>
<ul>
<li>Raspberry PI 3 Model B v1.2</li>
<li><a href="https://www.adafruit.com/product/1603">BMP-180 I2C Bosch</a> temperature and atmospheric pressure sensor</li>
<li><a href="https://www.adafruit.com/product/1899">HTU-21D I2C</a> temperature and relative humidity sensor</li>
</ul>
<p><img loading="lazy" decoding="async" width="750" height="488" src="https://lighty.io/wp-content/uploads/2018/03/rpi-1024x666.png" alt="" srcset="https://lighty.io/wp-content/uploads/2018/03/rpi-1024x666.png 1024w, https://lighty.io/wp-content/uploads/2018/03/rpi-300x195.png 300w, https://lighty.io/wp-content/uploads/2018/03/rpi-768x499.png 768w" sizes="(max-width: 750px) 100vw, 750px"></p>
<h3>Software Stack</h3>
<p>The software stack used on the Raspberry PI device consists of following components:</p>
<ul>
<li><a href="https://www.raspberrypi.org/downloads/raspbian/">Raspbian Stretch Lite</a></li>
<li><a href="http://openjdk.java.net/">OpenJDK 8</a></li>
<li><a href="http://wiringpi.com/">Wiring Pi</a></li>
<li><a href="http://pi4j.com/">pi4j</a></li>
<li><a href="https://lighty.io/download">lighty.io</a></li>
</ul>
<p><img loading="lazy" decoding="async" width="336" height="208" src="https://lighty.io/wp-content/uploads/2018/04/raspberry-software-stack.png" alt="" srcset="https://lighty.io/wp-content/uploads/2018/04/raspberry-software-stack.png 336w, https://lighty.io/wp-content/uploads/2018/04/raspberry-software-stack-300x186.png 300w" sizes="(max-width: 336px) 100vw, 336px" class="aligncenter"></p>
<p>The next step is to create a YANG model of the device:</p>
<pre data-enlighter-language="python">module rpi-device {
    yang-version 1.1;
    namespace "urn:tech.pantheon.netconfdevice.rpid";
    prefix "dc";
    organization "Pantheon Technologies";
    description
        "This module represents API to Raspberry-Pi test device";
    revision "2018-02-25" {
        description
            "Initial revision";
    }
    grouping led-data {
        leaf led-id {
             type int8 {
                  range "0 .. 3";
             }
             description "Unique LED port ID. Allowed values are 0,1,2,3.";
        }
        leaf led-status {
             type boolean;
             description "LED port status true=high/on, false=low/off.";
        }
    }
    container RpiDevice {
        description "Data model of RPis test device.";
        leaf device-name {
            type string;
            description "Name of this device.";
        }
        leaf temperature {
            type decimal64 {
                 fraction-digits 3;
                 range "-200 .. 200";
            }
            config false;
            description "Ambient temperature in Celsius degree [C].";
        }
        leaf relative-humidity {
            type decimal64 {
                 fraction-digits 3;
                 range "0 .. 100";
            }
            config false;
            description "Ambient relative humidity in percentage [%].";
        }
        leaf atmospheric-pressure {
            type decimal64 {
                 fraction-digits 3;
                 range "0 .. 1000000";
            }
            config false;
            description "Atmospheric Pressure in pascals [Pa].";
        }
        list led-indicators {
             config false;
             description "0-3 LED port indicator list";
             key "led-id";
             uses led-data;
        }
    }
    rpc set-led {
        description "set LED port status high/on or low/off.";
        input {
           uses led-data;
        }
        output {
           uses led-data;
        }
    }
}
</pre>
<p>The last step is to implement the Java code, which initializes the NETCONF stack, datastore, and hardware bindings.</p>
<p>These interact with the sensors and IO ports of Raspberry PI. Example below starts NETCONF interface on port 17830. The <a href="mailto:rpi-device@2018-02-25.yang">rpi-device@2018-02-25.yang</a> YANG model is used and the device Datastore is initialized with data from configuration.</p>
<p>Hardware drivers for sensors and IO ports are injected using constructors. The main class, which starts the NETCONF device application, looks like this:</p>
<pre data-enlighter-language="python">public static void main(String[] args) {
    //1. Load models from classpath
    Set&lt;YangModuleInfo&gt; rpiModules = ModelUtils.getModelsFromClasspath(ModuleId.from("rpi-device", "2018-02-25"));
    //2. Initialize DataStores
    InputStream initialDataConfig = Main.class.getResourceAsStream("/initial-config.xml");
    InputStream initialDataOperational = Main.class.getResourceAsStream("/initial-operational.xml");
    //3. Initialize hardware driver
    HardwareDriver hardwareDriver = HardwareDriverFactory.create();
    //4. Initialize RPCs
    RpiDeviceServiceImpl rpiDeviceService = new RpiDeviceServiceImpl(hardwareDriver);
    SetLedProcessor setLedProcessor = new SetLedProcessor(rpiDeviceService);
    //5. Initialize Netconf device
    NetconfDevice netconfDevice = new NetconfDeviceBuilder()
            .setCredentials("admin", "admin")
            .setBindingPort(17830)
            .setInitialConfigurationData(initialDataConfig)
            .setInitialOperationalData(initialDataOperational)
            .withModels(rpiModules)
            .withDefaultRequestProcessors()
            .withRequestProcessor(setLedProcessor)
            .withDefaultCapabilities()
            .build();
    netconfDevice.start();
    //6. Initialize hardware scanner
    DataStoreService dataStoreService = new DataStoreService(netconfDevice.getNetconfDeviceServices().getDataBroker());
    hardwareDriver.setListener(dataStoreService);
    HardwareScanner hardwareScanner = new HardwareScanner(dataStoreService, hardwareDriver, TimeUnit.SECONDS, 5);
    new Thread(hardwareScanner).start();
}
</pre>
<p>Now we have NETCONF device up and running on network, let’s use <strong>lighty-netconf-restconf-app</strong> as a SDN controller to manage this device.</p>
<p>This lighty.io based controller uses OpenDaylight core components, NETCONF south-bound plugin and Pantheon’s RESTCONF RFC8040 implementation as a north-bound plugin. Whole SDN architecture looks like this:</p>
<p><img loading="lazy" decoding="async" width="297" height="446" src="https://lighty.io/wp-content/uploads/2018/03/SDN-controlled.png" alt="" srcset="https://lighty.io/wp-content/uploads/2018/03/SDN-controlled.png 297w, https://lighty.io/wp-content/uploads/2018/03/SDN-controlled-200x300.png 200w" sizes="(max-width: 297px) 100vw, 297px"></p>
<p>Now we can use RESTCONF to connect and access Raspberry PI NETCONF device in 4 easy steps:</p>
<ol>
<li><strong>Connect the device to the SDN controller</strong></li>
</ol>
<p>POST <a href="https://localhost:8888/restconf/data/network-topology:network-topology/topology=topology-netconf" target="_blank" rel="noopener noreferrer">https://localhost:8888/restconf/data/network-topology:network-topology/topology=topology-netconf</a></p>
<pre data-enlighter-language="python">  {
    "netconf-topology:node" :[ {
      "node-id": "rpi-device",
      "host": "192.68.0.102",
      "port": 17830,
      "username": "admin",
      "password": "admin",
      "tcp-only": false,
      "keepalive-delay": 0,
      "netconf-node-configuration:schemaless": false
      }
    ]
  }
reply 201
</pre>
<ol start="2">
<li><strong>Check the device connection status</strong></li>
</ol>
<p>GET <a href="https://localhost:8888/restconf/data/network-topology:network-topology/topology=topology-netconf?content=nonconfig">https://localhost:8888/restconf/data/network-topology:network-topology/topology=topology-netconf?content=nonconfig</a></p>
<pre data-enlighter-language="python">reply 200:
{
    "topology": [
        {
            "topology-id": "topology-netconf",
            "node": [
                {
                    "node-id": "toaster-device",
                    "netconf-node-topology:available-capabilities": {
                        "available-capability": [
                            {
                                "capability": "urn:ietf:params:netconf:base:1.1",
                                "capability-origin": "device-advertised"
                            },
                            {
                                "capability": "urn:ietf:params:netconf:base:1.0",
                                "capability-origin": "device-advertised"
                            },
                            {
                                "capability": "urn:ietf:params:netconf:capability:candidate:1.0",
                                "capability-origin": "device-advertised"
                            },
                            {
                                "capability": "(urn:tech.pantheon.netconfdevice.rpid?revision=2018-02-25)rpi-device",
                                "capability-origin": "device-advertised"
                            }
                        ]
                    },
                    "netconf-node-topology:host": "127.0.0.1",
                    "netconf-node-topology:unavailable-capabilities": {},
                    "netconf-node-topology:connection-status": "connected",
                    "netconf-node-topology:port": 17830
                }
            ]
        }
    ]
}
</pre>
<ol start="3">
<li><strong>Access the device data</strong></li>
</ol>
<p>GET <a href="https://localhost:8888/restconf/data/network-topology:network-topology/topology=topology-netconf/node=rpi-device/yang-ext:mount/rpi-device:RpiDevice">https://localhost:8888/restconf/data/network-topology:network-topology/topology=topology-netconf/node=</a><a href="https://localhost:8888/restconf/data/network-topology:network-topology/topology=topology-netconf/node=rpi-device/yang-ext:mount/rpi-device:RpiDevice">rpi</a><a href="https://localhost:8888/restconf/data/network-topology:network-topology/topology=topology-netconf/node=rpi-device/yang-ext:mount/rpi-device:RpiDevice">-device/yang-ext:mount/rpi-device:RpiDevice</a></p>
<pre data-enlighter-language="python">reply 200
{
    "RpiDevice": {
        "atmospheric-pressure": 111111.109375,
        "device-name": "RPi device 01",
        "led-indicators": [
            {
                "led-id": 0,
                "led-status": true
            },
            {
                "led-id": 1,
                "led-status": false
            },
            {
                "led-id": 2,
                "led-status": false
            },
            {
                "led-id": 3,
                "led-status": false
            }
        ],
        "temperature": 22.2199993133544921875,
        "relative-humidity": 44.439998626708984375
    }
}
</pre>
<ol start="4">
<li><strong>Set the device LED port status</strong></li>
</ol>
<p>POST <a href="https://localhost:8888/restconf/operations/network-topology:network-topology/topology=topology-netconf/node=rpi-device/yang-ext:mount/rpi-device:set-led">https://localhost:8888/restconf/operations/network-topology:network-topology/topology=topology-netconf/node=</a><a href="https://localhost:8888/restconf/operations/network-topology:network-topology/topology=topology-netconf/node=rpi-device/yang-ext:mount/rpi-device:set-led">rpi</a><a href="https://localhost:8888/restconf/operations/network-topology:network-topology/topology=topology-netconf/node=rpi-device/yang-ext:mount/rpi-device:set-led">-device/yang-ext:mount/rpi-device:set-led</a></p>
<pre data-enlighter-language="python">{
	"input": {
		"led-id": 0,
		"led-status": true
	}
}
reply 200:
{
    "output": {
        "led-status": true,
        "led-id": 0
    }
}
</pre>
<p>This example shows you, how easily you can create your own YANG model, to be able to manage your embedded devices with lighty.io SDN controller.</p>
<p>If you don’t dare to write your own YANG models, you can search for opensource models from standard bodies like IETF, or Openconfig.net.</p>
<p>Juraj Veverka</p>
<p>The post <a href="https://lighty.io/lighty-io-netconf-device-on-arm/">lighty.io NETCONF Device on ARM</a> appeared first on <a href="https://lighty.io">lighty.io</a>.</p>
]]></content:encoded>
					
		
		
			</item>
	</channel>
</rss>
