在odl中怎样实现rpc
opendaylight作为sdn主要开源项目,採用osgi框架。已经得到非常多厂商的支持。氦版本号也公布在即。
以下介绍一下在odl中怎样实现rpc. odl使用yang作为model模型定义文件。yang规范最先被用于netconf,后来restconf在http协议上实现restful。而採用yang定义模型。
实现分2步:1.採用yang定义模型,实现api jar包。2 实现rpc service的实现类,注冊到session中。
2个java的project文件夹结构。
第一步:定义yang文件及其pom.xml
在文件夹xptest\src\main\yang下定义xptest.yang
module xptest { yang-version 1; namespace "http://startsky.com/ns/xptest"; prefix xps; organization "xpstudio Netconf Central"; contact "xinping <xpzh@sohu.com>"; description "YANG version of the xptest-MIB."; revision "2014-10-3" { description "xptest module in progress."; } typedef DispString { type string { length "0 .. 255"; } description "YANG version of the SMIv2 DisplayString TEXTUAL-CONVENTION."; reference "RFC 2579, section 2."; } container xptester { leaf name { type string; } leaf age { type uint32; default 99; } leaf homeaddress { type string; } } // container toaster rpc make-order { input { leaf name { type string; } leaf days { type uint32; default 1; } } output { leaf name { type string; } leaf orderno { type uint32; } } } // make-order rpc cancel-order { input { leaf orderno { type uint32; } } output { leaf name { type string; } leaf order-status { type enumeration { enum "success" { value 1; } enum "fail" { value 2; } } } } } // cancel-order } // module xptest
定义yang的pom.xml,在xptest下定义pom.xml
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.opendaylight.controller.samples</groupId> <artifactId>sal-samples</artifactId> <version>1.2.0-SNAPSHOT</version> </parent> <artifactId>sample-xptest</artifactId> <packaging>bundle</packaging> <dependencies> <dependency> <groupId>org.opendaylight.yangtools</groupId> <artifactId>yang-binding</artifactId> </dependency> <dependency> <groupId>org.opendaylight.yangtools</groupId> <artifactId>yang-common</artifactId> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.opendaylight.yangtools</groupId> <artifactId>yang-maven-plugin</artifactId> <dependencies> <dependency> <groupId>org.opendaylight.yangtools</groupId> <artifactId>maven-sal-api-gen-plugin</artifactId> <version>${yangtools.version}</version> <type>jar</type> </dependency> </dependencies> <executions> <execution> <goals> <goal>generate-sources</goal> </goals> <configuration> <yangFilesRootDir>src/main/yang</yangFilesRootDir> <codeGenerators> <generator> <codeGeneratorClass>org.opendaylight.yangtools.maven.sal.api.gen.plugin.CodeGeneratorImpl</codeGeneratorClass> <outputBaseDir>${salGeneratorPath}</outputBaseDir> </generator> </codeGenerators> <inspectDependencies>true</inspectDependencies> </configuration> </execution> </executions> </plugin> </plugins> </build> <scm> <connection>scm:git:ssh://git.opendaylight.org:29418/controller.git</connection> <developerConnection>scm:git:ssh://git.opendaylight.org:29418/controller.git</developerConnection> <tag>HEAD</tag> <url>https://wiki.opendaylight.org/view/OpenDaylight_Controller:MD-SAL</url> </scm> </project>
上面yang文件定义了两个rpc。
执行mvn install编译xptest.yang. 会产生一个rpc服务XptestService 接口。当中两个方法相应两个rpc 函数。第二步:定义rpc的实现文件XpTestProvider及其Activator
该project定义为xpprovider。
rpc实现类XpTestProvider
package org.opendaylight.controller.xptest.impl; import java.io.File; import java.util.concurrent.Future; //import org.opendaylight.controller.xptest.Activator; import org.opendaylight.yang.gen.v1.http.startsky.com.ns.xptest.rev141003.CancelOrderInput; import org.opendaylight.yang.gen.v1.http.startsky.com.ns.xptest.rev141003.CancelOrderOutput; import org.opendaylight.yang.gen.v1.http.startsky.com.ns.xptest.rev141003.CancelOrderOutput.OrderStatus; import org.opendaylight.yang.gen.v1.http.startsky.com.ns.xptest.rev141003.CancelOrderOutputBuilder; import org.opendaylight.yang.gen.v1.http.startsky.com.ns.xptest.rev141003.MakeOrderInput; import org.opendaylight.yang.gen.v1.http.startsky.com.ns.xptest.rev141003.MakeOrderOutput; import org.opendaylight.yang.gen.v1.http.startsky.com.ns.xptest.rev141003.MakeOrderOutputBuilder; import org.opendaylight.yang.gen.v1.http.startsky.com.ns.xptest.rev141003.XptestService; import org.opendaylight.yangtools.yang.common.RpcResult; import org.opendaylight.yangtools.yang.common.RpcResultBuilder; import org.opendaylight.yangtools.yang.common.RpcError.ErrorType; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.common.util.concurrent.Futures; public class XpTestProvider implements XptestService { private final static Logger LOG = LoggerFactory.getLogger(XpTestProvider.class); @Override public Future<RpcResult<CancelOrderOutput>> cancelOrder( CancelOrderInput input) { // TODO Auto-generated method stub RpcResult<CancelOrderOutput> ret=null; if(input.getOrderno() >10) { ret=RpcResultBuilder.<CancelOrderOutput>failed().withError( ErrorType.APPLICATION, "resource-denied", "days > 10,failed!!" ).build(); }else { CancelOrderOutputBuilder builder=new CancelOrderOutputBuilder(); builder.setName("name"+input.getOrderno()); builder.setOrderStatus(OrderStatus.Success); ret=RpcResultBuilder.<CancelOrderOutput>success(builder.build()).build(); } return Futures.immediateFuture(ret); } @Override public Future<RpcResult<MakeOrderOutput>> makeOrder(MakeOrderInput input) { // TODO Auto-generated method stub RpcResult<MakeOrderOutput> ret=null; LOG.info( "user.dir "+System.getProperty("user.dir")); File directory = new File("");//设定为当前目录 try{ LOG.info("std: "+directory.getCanonicalPath());//获取标准的路径 LOG.info("abs: "+directory.getAbsolutePath());//获取绝对路径 }catch(Exception e) { } if(input.getDays()>10) { ret=RpcResultBuilder.<MakeOrderOutput>failed().withError( ErrorType.APPLICATION, "resource-denied", "days > 10,failed!!" ).build(); }else { MakeOrderOutputBuilder builder=new MakeOrderOutputBuilder(); builder.setName(input.getName()); builder.setOrderno((long) 112233); ret=RpcResultBuilder.<MakeOrderOutput>success(builder.build()).build(); } return Futures.immediateFuture(ret); } }实现插件入口类Activator,顺便实现命令行接口,能够自己定义命令行測试命令。
/** * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0 which accompanies this distribution, * and is available at http://www.eclipse.org/legal/epl-v10.html */ package org.opendaylight.controller.xptest; import org.eclipse.osgi.framework.console.CommandInterpreter; import org.eclipse.osgi.framework.console.CommandProvider; import org.opendaylight.controller.sal.binding.api.AbstractBindingAwareProvider; import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext; import org.opendaylight.controller.xptest.impl.XpTestProvider; import org.opendaylight.yang.gen.v1.http.startsky.com.ns.xptest.rev141003.XptestService; import org.osgi.framework.BundleContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Forwarding Rules Manager Activator * * Activator {@link ForwardingRulesManager}. * It registers all listeners (DataChangeEvent, ReconcilNotification) * in the Session Initialization phase. * * @author <a href="mailto:vdemcak@cisco.com">Vaclav Demcak</a> * * */ public class Activator extends AbstractBindingAwareProvider implements CommandProvider { private final static Logger LOG = LoggerFactory.getLogger(Activator.class); @Override public void onSessionInitiated(ProviderContext session) { LOG.info("FRMActivator initialization."); try { // final DataBroker dataBroker = session.getSALService(DataBroker.class); // this.manager = new ForwardingRulesManagerImpl(dataBroker, session); // this.manager.start(); XpTestProvider rpcins=new XpTestProvider(); session.addRpcImplementation(XptestService.class,rpcins); LOG.info("FRMActivator initialization successfull."); } catch (Exception e) { LOG.error("Unexpected error by FRM initialization!", e); this.stopImpl(null); } } @Override protected void startImpl(BundleContext context) { // TODO Auto-generated method stub super.startImpl(context); context.registerService(CommandProvider.class.getName(), this, null); } @Override protected void stopImpl(final BundleContext context) { /* if (manager != null) { try { manager.close(); } catch (Exception e) { LOG.error("Unexpected error by stopping FRMActivator", e); } manager = null; }*/ LOG.info("FRMActivator stopped."); } public void _gettpsbyne(CommandInterpreter ci) { ci.println("gettpsbyne:" + ci.nextArgument()); } @Override public String getHelp() { return "\tgettpsbyne neid– say what you input\n"; } }
xpprovider的pom.xml文件。
<?xml version="1.0" encoding="UTF-8"?执行mvn install 编译,之后把这两个jar包复制到odl的plugins文件夹下,最好执行odl准备。> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.opendaylight.controller.samples</groupId> <artifactId>sal-samples</artifactId> <version>1.2.0-SNAPSHOT</version> </parent> <artifactId>sample-xptest-provider</artifactId> <packaging>bundle</packaging> <dependencies> <dependency> <groupId>${project.groupId}</groupId> <artifactId>sample-xptest</artifactId> <version>${project.version}</version> </dependency> <dependency> <groupId>equinoxSDK381</groupId> <artifactId>org.eclipse.osgi</artifactId> </dependency> <dependency> <groupId>org.opendaylight.controller</groupId> <artifactId>config-api</artifactId> </dependency> <dependency> <groupId>org.opendaylight.controller</groupId> <artifactId>sal-binding-api</artifactId> </dependency> <dependency> <groupId>org.opendaylight.controller</groupId> <artifactId>sal-binding-config</artifactId> </dependency> <dependency> <groupId>org.opendaylight.controller</groupId> <artifactId>sal-common-util</artifactId> </dependency> <dependency> <groupId>org.osgi</groupId> <artifactId>org.osgi.core</artifactId> </dependency> <!-- dependencies to use AbstractDataBrokerTest --> <dependency> <groupId>org.opendaylight.controller</groupId> <artifactId>sal-binding-broker-impl</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.opendaylight.controller</groupId> <artifactId>sal-binding-broker-impl</artifactId> <type>test-jar</type> <scope>test</scope> </dependency> <dependency> <artifactId>junit</artifactId> <groupId>junit</groupId> <scope>test</scope> </dependency> <!-- used to mock up classes --> <dependency> <groupId>org.mockito</groupId> <artifactId>mockito-all</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.opendaylight.controller</groupId> <artifactId>sal-binding-api</artifactId> </dependency> <dependency> <groupId>org.opendaylight.controller.model</groupId> <artifactId>model-flow-service</artifactId> </dependency> <dependency> <groupId>org.opendaylight.yangtools</groupId> <artifactId>yang-common</artifactId> </dependency> <dependency> <groupId>org.opendaylight.controller</groupId> <artifactId>sal-binding-broker-impl</artifactId> <scope>provided</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.apache.felix</groupId> <artifactId>maven-bundle-plugin</artifactId> <configuration> <instructions> <Bundle-Activator>org.opendaylight.controller.xptest.Activator</Bundle-Activator> </instructions> </configuration> </plugin> </plugins> </build> <scm> <connection>scm:git:ssh://git.opendaylight.org:29418/controller.git</connection> <developerConnection>scm:git:ssh://git.opendaylight.org:29418/controller.git</developerConnection> <tag>HEAD</tag> <url>https://wiki.opendaylight.org/view/OpenDaylight_Controller:MD-SAL</url> </scm> </project>
第三步:进行測试。
执行run.bat,启动odl,在restclient中执行以下測试用例。
能够做restclient的工具有chrome插件postman,firefox的restclient,网上还有个单独jar包restclient.
HTTP Method => POST
URL => http://localhost:8080/restconf/operations/xptest:make-order
Header => Content-Type: application/yang.data+json
Body =>
{
"input" :
{
"xptest:name" : "3","xptest:days":3
}
}
能够看到返回xml数据, response header
- Status Code: 200 OK
- Content-Type: application/xml
- Date: Wed, 08 Oct 2014 12:43:29 GMT
- Server: Apache-Coyote/1.1
- Transfer-Encoding: chunked
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <output xmlns="http://startsky.com/ns/xptest"> <name>3</name> <orderno>112233</orderno> </output>
假设header中加accept:application/yang.data+json,将返回json数据。
按上面代码中意图能够构造失败測试用例。
希望本文对odl有兴趣的人,可以给予帮助。