MD-SAL:Toaster Step-By-Step krb
https://wiki.opendaylight.org/view/OpenDaylight_Controller:MD-SAL:Toaster_Step-By-Step_krb
https://wiki.opendaylight.org/view/OpenDaylight_Controller:MD-SAL:Toaster_Step-By-Step
https://wiki.opendaylight.org/view/OpenDaylight_Controller:MD-SAL:Toaster_Tutorial
以下教程将详细介绍预构建的Toaster示例,并逐步介绍Toaster示例,如同从头开始重新创建一样。 我们将从简单的定义开始,只允许访问操作数据,并推进到演示MD-SAL的许多方面的完整示例,包括通过JMX和restconf的远程过程调用,通过JMX访问状态数据,通知和 消费服务。 您可以按照步骤,实际创建新项目并执行它们,或通过简单地阅读和学习预构建代码。 不管怎样,这个练习对于理解一般来说从头开始构建MD-SAL插件需要做些什么。
1.Define the Toaster yang data model
2.Generate the Toaster yang data model source
在上面的代码中,DataBroker依赖项已经被MD-SAL注入,并且通过在生成的基类中定义的getDataBrokerDependency()方法可用。 自动注入通过我们在toaster-provider-impl.yang文件中定义的依赖性增强来实现。 createInstance()的返回类型是AutoCloseable。 我们必须返回一个AutoCloseable对象,因此MD-SAL可以通知我们的逻辑什么时候关闭。 在本示例中,我们不需要在ToasterProviderModuleFactory中修改或实现任何内容。 注1:该领域的未来增强可以是通过自动执行更多注册等来简化这里的注册过程。 今天,这是您需要执行这些注册的方式。
https://wiki.opendaylight.org/view/OpenDaylight_Controller:MD-SAL:Toaster_Step-By-Step
https://wiki.opendaylight.org/view/OpenDaylight_Controller:MD-SAL:Toaster_Tutorial
以下教程将详细介绍预构建的Toaster示例,并逐步介绍Toaster示例,如同从头开始重新创建一样。 我们将从简单的定义开始,只允许访问操作数据,并推进到演示MD-SAL的许多方面的完整示例,包括通过JMX和restconf的远程过程调用,通过JMX访问状态数据,通知和 消费服务。 您可以按照步骤,实际创建新项目并执行它们,或通过简单地阅读和学习预构建代码。 不管怎样,这个练习对于理解一般来说从头开始构建MD-SAL插件需要做些什么。
Part 1: Defining an Operational Toaster
1.Define the Toaster yang data model
2.Generate the Toaster yang data model source
3.Implement the operational Toaster provider (OpendaylightToaster)
4.Wiring the OpendaylightToaster service
4.Wiring the OpendaylightToaster service
5.Generate the Toaster yang provider source
6.Implement the ToasterProviderModule
6.Implement the ToasterProviderModule
定义了toaster service的实现和需要的MD-SAL服务(data-broker,用于储存操作数据)
1.Define the Toaster yang data model
第一个yang文件toaster.yang定义了可以由北向客户端(例如restconf API)访问的烤面包机数据模型的北向抽象,特别是其属性,RPC和通知。 This file is located in the sample-toaster project under the src/main/yang source folder.
//This file contains a YANG data definition. This data model defines
//a toaster, which is based on the SNMP MIB Toaster example
module toaster {
//The yang version - today only 1 version exists. If omitted defaults to 1.
yang-version 1;
//a unique namespace for this toaster module, to uniquely identify it from other modules that may have the same name.
namespace
"http://netconfcentral.org/ns/toaster";
//a shorter prefix that represents the namespace for references used below
prefix toast;
organization "Netconf Central";
contact
"Andy Bierman <andy@netconfcentral.org>";
description
"YANG version of the TOASTER-MIB.";
//defines the dates of revisions for this yang file
revision "2009-11-20" {
description
"Toaster module in progress.";
}
//declares a base identity, in this case a base type for different types of toast.
identity toast-type {
description
"Base for all bread types supported by the toaster. New bread types not listed here nay be added in the future.";
}
//the below identity section is used to define globally unique identities
//Note - removed a number of different types of bread to shorten the text length.
identity white-bread {
base toast:toast-type; //logically extending the declared toast-type above.
description "White bread."; //free text description of this type.
}
identity wheat-bread {
base toast-type;
description "Wheat bread.";
}
//defines a new "Type" string type which limits the length
typedef DisplayString {
type string {
length "0 .. 255";
}
description
"YANG version of the SMIv2 DisplayString TEXTUAL-CONVENTION.";
reference
"RFC 2579, section 2.";
}
// This definition is the top-level configuration "item" that defines a toaster. The "presence" flag connotes there can only be one instance of a toaster which, if present, indicates the service is available.//这个定义是定义烤面包机的顶层配置“item”。 “presence”标志意味着只能有一个烤面包机的一个实例,如果存在,则表示服务可用。
container toaster {
presence
"Indicates the toaster service is available";
description
"Top-level container for all toaster database objects.";
//Note in these three attributes that config = false. This indicates that they are operational attributes.
leaf toasterManufacturer {
type DisplayString;
config false;
mandatory true;
description
"The name of the toaster's manufacturer. For instance, Microsoft Toaster.";
}
leaf toasterModelNumber {
type DisplayString;
config false;
mandatory true;
description
"The name of the toaster's model. For instance, Radiant Automatic.";
}
leaf toasterStatus {
type enumeration {
enum "up" {
value 1;
description
"The toaster knob position is up. No toast is being made now.";
}
enum "down" {
value 2;
description
"The toaster knob position is down. Toast is being made now.";
}
}
config false;
mandatory true;
description
"This variable indicates the current state of the toaster.";
}
} // container toaster
} // module toaster
You can see above that we marked all three of the leaf attributes on the toaster container as operational (config false), instead of configuration data. MD-SAL, along with some ietf drafts for restconf split the configuration and operational data into two separate data stores.
你可以看到上面我们将toaster容器上的所有三个叶子属性标记为operational (config false),而不是配置数据。 MD-SAL以及一些用于restconf的ietf草稿将配置和操作数据分成两个单独的数据存储。
- Operational - Operational data stores are used to show the running state (read only) view of the devices, network, services, etc that you might be looking at. In our case we have a service called toaster which is available - the manufacture, model and status of the toaster are all provided by the underlying toaster and can not be configured (later we will add a configuration attribute). Think of the first two attributes as constants which are hardcoded into the physical device, while the third is a representation of current state, and changes as the toaster is used.
- Config - Config data stores are generally used to configure the device in someway. These configurations are user provided and is a way for the user to tell the device how to behave. For example if you wanted to configure the resource in some way, such as applying a policy or other configuration then you would use this data store. We will add some configuration data in part 3 of this tutorial.
操作 - 操作数据存储用于显示您可能正在查看的设备,网络,服务等的运行状态(只读)视图。 在我们的例子中,我们有一个称为烤面包机的服务可用 - 烤面包机的制造,型号和状态都由底层烤面包机提供,不能配置(以后我们将添加一个配置属性)。 将前两个属性视为硬编码到物理设备中的常量,而第三个属性是当前状态的表示,以及使用烤面包机时的更改。
配置 - 配置数据存储通常用于在某个时间配置设备。 这些配置是用户提供的,并且是用户告诉设备如何行为的一种方式。 例如,如果您想以某种方式配置资源(例如应用策略或其他配置),那么您将使用此数据存储。 我们将在本教程的第3部分中添加一些配置数据。
2.Generate the Toaster yang data model source
我们为烤面包机定义了数据模型,现在我们需要一个实现来提供操作数据。 我们将创建一个类OpendaylightToaster。 在初始化时,它通过DataBroker接口将操作烤面包机数据operational toaster data写入MD-SAL的数据存储,并在关闭时删除数据。 该类的最终版本可以在sample-toaster-provider项目的src / main / java源文件夹下找到。 在单独的项目 in a separate project中创建此类的原因是它允许数据模型和实现由不同的bundle提供,因此允许不同的bundle定义相同数据模型的不同实现。 然而,如果实现是专有的,没有什么阻止我们把一切都放在同一个包中。
配置 - 配置数据存储通常用于在某个时间配置设备。 这些配置是用户提供的,并且是用户告诉设备如何行为的一种方式。 例如,如果您想以某种方式配置资源(例如应用策略或其他配置),那么您将使用此数据存储。 我们将在本教程的第3部分中添加一些配置数据。
2.Generate the Toaster yang data model source
At this point we can compile the yang data model to generate the java source files. To do this, we need to specify the yang-maven-plugin in the pom.xml:
<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"> ... <build> <plugins> <plugin> <groupId>org.opendaylight.yangtools</groupId> <artifactId>yang-maven-plugin</artifactId> <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> <dependencies> <dependency> <groupId>org.opendaylight.yangtools</groupId> <artifactId>maven-sal-api-gen-plugin</artifactId> <version>${yangtools.version}</version> <type>jar</type> </dependency> </dependencies> </plugin> </plugins> </build> <dependencies> <dependency> <groupId>org.opendaylight.yangtools</groupId> <artifactId>yang-binding</artifactId> </dependency> <dependency> <groupId>org.opendaylight.controller</groupId> <artifactId>sal-common-util</artifactId> </dependency> <dependency> <groupId>org.opendaylight.yangtools</groupId> <artifactId>yang-common</artifactId> </dependency> </dependencies> ... </project>
The yang-maven-plugin is used to generate java source from yang definition files. Much of the plugin's configuration is boilerplate样板. Tags of specific interest:
- yangFilesRootDir - specifies the directory under the project to locate yang files to process. This defaults to src/main/yang.
- codeGeneratorClass - specifies the code generator to use. CodeGeneratorImpl is used to generate classes that represent the yang data model components.
- outputBaseDir - specifies the output directory for the generated classes. In the controller project we specify the ${salGeneratorPath} property which is defined in the root pom as src/main/yang-gen-sal.
Next, run:
mvn clean install
Note: You really only need to run 'mvn install' here since we have nothing to clean, but running a clean will not harm anything and is a good practice to ensure your generated code is cleaned up correctly so new code can be generated.
Now you will see java class files generated under src/main/yang-gen-sal. Classes of note:
- Toaster - an interface that represents the toaster container with methods to obtain the leaf node data.
- ToasterData - an interface that represents the top-level toaster module with one method getToaster() that returns the singleton toaster instance.
- WheatBread, WhiteBread, etc' - abstract classes that represent the various toast types.
- $YangModelBindingProvider, $YangModuleInfoImpl - these are used internally by MD-SAL to wire the toaster module for use. More on this later.
3.Implement the operational Toaster provider (OpendaylightToaster)
我们为烤面包机定义了数据模型,现在我们需要一个实现来提供操作数据。 我们将创建一个类OpendaylightToaster。 在初始化时,它通过DataBroker接口将操作烤面包机数据operational toaster data写入MD-SAL的数据存储,并在关闭时删除数据。 该类的最终版本可以在sample-toaster-provider项目的src / main / java源文件夹下找到。 在单独的项目 in a separate project中创建此类的原因是它允许数据模型和实现由不同的bundle提供,因此允许不同的bundle定义相同数据模型的不同实现。 然而,如果实现是专有的,没有什么阻止我们把一切都放在同一个包中。
public class OpendaylightToaster implements AutoCloseable{
InstanceIdentifier<Toaster> TOASTER_IID = InstanceIdentifier.builder(Toaster.class).build();
DisplayString TOASTER_MANUFACTURER = new DisplayString("Opendaylight");
DisplayString TOASTER_MODEL_NUMBER = new DisplayString("Model 1 - Binding Aware");
private DataBroker dataProvider;
private Toaster buildToaster( ToasterStatus status ) { // note - we are simulating a device whose manufacture and model are // fixed (embedded) into the hardware. // This is why the manufacture and model number are hardcoded. return new ToasterBuilder().setToasterManufacturer( TOASTER_MANUFACTURER ) .setToasterModelNumber( TOASTER_MODEL_NUMBER ) .setToasterStatus( status ) .build(); }
public void setDataProvider( final DataBroker salDataProvider ) { this.dataProvider = salDataProvider; setToasterStatusUp( null ); }
public void close() throws ExecutionException, InterruptedException { if (dataProvider != null) { WriteTransaction t = dataProvider.newWriteOnlyTransaction(); t.delete(LogicalDatastoreType.OPERATIONAL,TOASTER_IID); ListenableFuture<RpcResult<TransactionStatus>> future = t.commit(); Futures.addCallback( future, new FutureCallback<RpcResult<TransactionStatus>>() { @Override public void onSuccess( RpcResult<TransactionStatus> result ) { LOG.debug( "Delete Toaster commit result: " + result ); } @Override public void onFailure( Throwable t ) { LOG.error( "Delete of Toaster failed", t ); } } ); } }
private void setToasterStatusUp( final Function<Boolean,Void> resultCallback ) {
WriteTransaction tx = dataProvider.newWriteOnlyTransaction(); tx.put( LogicalDatastoreType.OPERATIONAL,TOASTER_IID, buildToaster( ToasterStatus.Up ) ); ListenableFuture<RpcResult<TransactionStatus>> commitFuture = tx.commit(); Futures.addCallback( commitFuture, new FutureCallback<RpcResult<TransactionStatus>>() { @Override public void onSuccess( RpcResult<TransactionStatus> result ) { if( result.getResult() != TransactionStatus.COMMITED ) { LOG.error( "Failed to update toaster status: " + result.getErrors() ); } notifyCallback( result.getResult() == TransactionStatus.COMMITED ); } @Override public void onFailure( Throwable t ) { // We shouldn't get an OptimisticLockFailedException (or any ex) as no // other component should be updating the operational state. LOG.error( "Failed to update toaster status", t ); notifyCallback( false ); } void notifyCallback( boolean result ) { if( resultCallback != null ) { resultCallback.apply( result ); } } } ); } }
4.Wiring the OpendaylightToaster service
We've implemented the toaster provider service - now we have to get our OpendaylightToaster instantiated and wired up with the MD-SAL. There's a couple ways to do this - we're going to use the config subsystem which provides service lifecycle management and also provides configuration access through JMX and NETCONF. The config subsystem is separate from MD-SAL and is used to instantiate and wire the toaster service to MD-SAL.
We first need to describe our OpendaylightToaster service configuration and what dependent services it needs. This is defined in... you guessed it, yang.
我们已经实现了toaster provider service,现在要开始实例化OpendaylightToaster并接上 MD-SAL。我们可以用config subsystem,它提供了服务周期管理并支持通过JMX and NETCONF进行configuration。
这个config subsystem与MD-SAL是分开的,它用于实例化toaster service并将它接上MD-SAL。
我们首先描述OpendaylightToaster service 的配置,和它的依赖服务。
1.Define the Toaster provider service yang configuration
Next we'll define a yang module that describes the configuration of the toaster provider service in the toaster-provider-impl.yang file:
module toaster-provider-impl { yang-version 1; namespace "urn:opendaylight:params:xml:ns:yang:controller:config:toaster-provider:impl"; prefix "toaster-provider-impl"; import config { prefix config; revision-date 2013-04-05; } import opendaylight-md-sal-binding { prefix mdsal; revision-date 2013-10-28; } description "This module contains the base YANG definitions for toaster-provider impl implementation."; revision "2014-01-31" { description "Initial revision."; } // This is the definition of the service implementation as a module identity 服务实现作为module identity identity toaster-provider-impl { base config:module-type; // Specifies the prefix for generated java classes. config:java-name-prefix ToasterProvider; } // Augments the 'configuration' choice node under modules/module. augment "/config:modules/config:module/config:configuration" { case toaster-provider-impl { when "/config:modules/config:module/config:type = 'toaster-provider-impl'"; //wires in the data-broker service container data-broker { uses config:service-ref { refine type { mandatory false; config:required-identity mdsal:binding-async-data-broker; } } } } } }
The toaster-provider-impl identity is a module-type identity that defines a global identifier for the toaster-provider service implementation so that it can be referred to.
The augmentation of the modules/module/configuration hierarchy choice-type node adds schema nodes specific to the toaster-provider-impl module identity type (as indicated by the 'when' clause). This is where we define configuration information needed to initialize the toaster-provider-impl module; specifically, which external service dependencies are needed. We see that the OpendaylightToaster needs the DataBroker so we add a data-broker container node that defines a dependency on the MD-SAL's DataBroker service. Syntactically, it defines a reference (of type service-ref) to the particular service instance referred to by the mdsal:binding-async-data-broker service identity. The service instance is set at runtime by the MD-SAL.
toaster-provider-impl identity 是一个module-type identity,定义了烤面包器提供者服务实现的全局标识符,以便可以参考。
modules/module/configuration 层次结构,augmentation 添加特定于toaster-provider-impl 的module identity type的schema nodes(如“when”子句所指示的)。
在这里定义了初始化toaster-provider-impl模块所需的配置信息; 就是说,需要哪些外部服务依赖性。
我们看到OpendaylightToaster需要DataBroker,因此我们添加了一个data-broker container node,该节点定义了对MD-SAL的DataBroker服务的依赖。
在语法上,它定义了由mdsal:binding-async-data-broker服务标识引用的特定服务实例的引用(类型为service-ref)。 服务实例在运行时由MD-SAL设置。
我们还需要在pom.xml文件中添加依赖关系,以便可以通过代码生成器找到opendaylight-md-sal-binding和config yang导入:
运行mvn clean安装后,您应该会看到生成的两个文件:
ToasterProviderlModule - 其createInstance()方法提供OpendaylightToaster实例的具体类。
ToasterProviderModuleFactory - 由创建ToasterProviderModule实例的MD-SAL在内部实例化的具体类。
注意:这两个类是在src / main / java下生成的,因为它们将包含手动编写的代码。
modules/module/configuration 层次结构,augmentation 添加特定于toaster-provider-impl 的module identity type的schema nodes(如“when”子句所指示的)。
在这里定义了初始化toaster-provider-impl模块所需的配置信息; 就是说,需要哪些外部服务依赖性。
我们看到OpendaylightToaster需要DataBroker,因此我们添加了一个data-broker container node,该节点定义了对MD-SAL的DataBroker服务的依赖。
在语法上,它定义了由mdsal:binding-async-data-broker服务标识引用的特定服务实例的引用(类型为service-ref)。 服务实例在运行时由MD-SAL设置。
5.Generate the Toaster yang provider source
为了生成便于 service wiring的java源文件,除了CodeGeneratorImpl之外,我们还需要在pom.xml中的yang-maven-plugin配置中添加另一个代码生成器JmxGenerator,以及对yangtools的附加依赖 插件:我们还需要在pom.xml文件中添加依赖关系,以便可以通过代码生成器找到opendaylight-md-sal-binding和config yang导入:
运行mvn clean安装后,您应该会看到生成的两个文件:
ToasterProviderlModule - 其createInstance()方法提供OpendaylightToaster实例的具体类。
ToasterProviderModuleFactory - 由创建ToasterProviderModule实例的MD-SAL在内部实例化的具体类。
注意:这两个类是在src / main / java下生成的,因为它们将包含手动编写的代码。
6.Implement the ToasterProviderModule
ToasterProviderModule类大多数是从代码生成完成的。 只有ToasterProviderModule.createInstance()方法需要实现来实例化和连线OpendaylightToaster: @Override
public java.lang.AutoCloseable createInstance() {
final OpendaylightToaster opendaylightToaster = new OpendaylightToaster();
DataBroker dataBrokerService = getDataBrokerDependency();
opendaylightToaster.setDataProvider(dataBrokerService);
// Wrap toaster as AutoCloseable and close registrations to md-sal at
// close(). The close method is where you would generally clean up thread pools
// etc.
final class AutoCloseableToaster implements AutoCloseable {
@Override
public void close() throws Exception {
opendaylightToaster.close();
}
}
return new AutoCloseableToaster();
}
在上面的代码中,DataBroker依赖项已经被MD-SAL注入,并且通过在生成的基类中定义的getDataBrokerDependency()方法可用。 自动注入通过我们在toaster-provider-impl.yang文件中定义的依赖性增强来实现。 createInstance()的返回类型是AutoCloseable。 我们必须返回一个AutoCloseable对象,因此MD-SAL可以通知我们的逻辑什么时候关闭。 在本示例中,我们不需要在ToasterProviderModuleFactory中修改或实现任何内容。 注1:该领域的未来增强可以是通过自动执行更多注册等来简化这里的注册过程。 今天,这是您需要执行这些注册的方式。
评论
发表评论