带你读《ODL技术内幕:架构设计与实现原理》之二:ODL项目管理设计详解

简介: ODL不仅仅是一个SDN控制器平台,它还是一个优秀的模型驱动架构实现,以及一个典型的分布式系统设计范例。通过ODL,我们能学习的不仅仅是SDN,也能学到其通用的编程技术及软件架构设计,其分布式系统设计实现也非常值得我们借鉴。

点击查看第一章
点击查看第三章
第2章

ODL项目管理设计详解

“罗马不是一天建成的”。同样,ODL也是历经多年才不断发展壮大。作为一个开源项目,在参与ODL的志愿者们的共同努力下,ODL在架构与项目管理方面持续得到演进,功能变得越来越多,架构日趋合理,项目管理的层次越来越清晰,社区及项目中的各种问题也逐步被解决。
在第1章我们了解到ODL采用了模块化的架构设计,现在ODL的子项目多达上百个,每个子项目又分为若干模块,可以说有数百个模块。这数百个模块从OSGi的视角来看就是几百个Bundle;从Maven的视角来看,就是几百个pom。对这种规模的项目进行管理不是一件容易的事情。因此,本章首先描述ODL社区在管理众多子项目过程中会遇到的若干问题,并将和读者一起回顾社区通过Maven工具解决这些问题的思路和设计原则,以及如何一步步优化并完善解决方案,最后给出社区总结的对于项目管理的最佳实践。

2.1 问题的提出

最初接触ODL项目时,笔者曾被它的庞大和繁杂吓到了。有个比喻说,“ODL是一只会跳舞的大象”。一方面是因为ODL包含了大量的功能特性;另一方面是因为最初的ODL版本中的各子项目是由参与创立ODL的各公司独立开发贡献到社区的,根本没有统一的架构设计,也很难做到统一的项目管理,而且一些子项目本身也没有进行很好的设计。比如,ODL最初的版本中,Cisco主导贡献的ODL最核心的框架部分:controller项目里,就有如下典型问题:

  • 该项目没有统一规划parent,比如mdsal就定义了两个parent:sal-parent和comp-atibility parent,版本号都是1.1-SNAPSHOT,但这两个parent都继承自另一个版本号为1.4.2-SNAPSHOT的parent pom。
  • 很多模块的版本号缺乏规划,没有从其直接的parent继承,使其定义混乱。比如UserManager的pom中,其parent的版本定义为1.4.2-SNAPSHOT,该模块的版本号却被定义成0.4.2-SNAPSHOT。
  • 依赖不是从parent pom继承,而是直接罗列在当前的pom中。

其他子项目也有类似的问题主要包括以下几个方面,1)整个ODL项目缺乏统一规划的parent pom,各模块继承层次不清晰,构建依赖混乱,版本编译构建和集成的工作经常出现各种问题,无法稳定;2)各项目和模块的版本号缺乏统一规划,导致ODL的子项目的几百个模块都有不同的版本号,维护与演进非常麻烦和困难;3)发布版本过程中,需要花费大量的人力修复出错的pom文件。
这些问题不仅给项目自身的维护和开发带来了困难,同时给学习和使用ODL的用户也带来了困扰。用户很难梳理清楚各项目和模块的不同版本,特别是ODL最初的几个发布版本。因此,用户在加载和运行初始发布的ODL版本的过程中,要面对非常多的干扰。

2.2 解决思路

所有用Maven管理的项目都应该是分模块的,每个模块都对应着一个pom.xml,pom.xml文件是Maven进行工作的主要配置文件。在这个文件中我们可以配置groupId、artifactId和version等Maven项目必需的元素,可以配置Maven项目需要使用的远程仓库,可以定义Maven项目打包的形式,也可以定义Maven项目的资源依赖关系等。对于一个最简单的pom.xml来说,必须包含modelVersion、groupId、artifactId和version这4个元素,当然其中的元素可以是从它的父项目中继承的。在Maven中,通过使用groupId、artifactId和version组成groupdId:artifactId:version的形式来确定唯一的一个项目(模块)。
对于如何处理所构建的多个模块间的关系,Maven给我们提供了一个pom的继承和聚合的功能。所谓聚合是可以通过一个pom将所有的要构建模块整合起来;所谓继承是在构建多个模块的时候,往往有多个模块会有相同的groupId、version或依赖,为了减少pom文件的配置,同面向对象的设计中类的继承一样,在父工程中配置了pom,子项目中的pom就可以继承。总之,聚合是为了方便高速构建项目,继承是为了消除重复配置,在简化pom的时候还能促进各个模块配置的一致性。两者的共同点是其packaging都是pom,聚合模块与继承关系中的父模块除了pom之外都没有实际内容。
ODL项目是通过Maven工具进行管理的,因此,对于上文ODL项目管理中碰到的问题,如何优化pom.xml的设计就是一个解决思路。对于公共编译配置和依赖管理的问题,ODL社区从第二个版本发布开始,成立了odlparent项目。该项目最初只有一个pom文件,这个pom文件里包含所有配置和依赖管理。顾名思义,这个项目的pom就是ODL所有其他项目的parent。从第1章我们了解到,ODL的模块是遵循OSGi规范而设计的,所有模块都要编译为bundle部署到OSGi容器里才能加载运行。因此,从第三个版本发布开始,bundle构建的公共配置也被放在odlparent中,也即bundle-parent。同时,编译构建bundle时的checkstyle配置文件也统一放在了odlparent项目中。第1章在搭建编译环境时,需要下载的Maven的settings.xml文件,也放到了odlparent中进行维护。在后续发布的版本中,odlparent项目中陆续加入了feature管理的parent,以及karaf打包的parent。这样,在ODL的子项目中,只需继承odlparent中相应的parent pom,就可继承这些公共配置,极大地简化了ODL子项目中pom的配置。
当然,我们不要忘了ODL的核心框架MD-SAL。在mdsal子项目中,有一个binding-parent的pom,这个pom包含了通过yangtools解析YANG模型所生成的binding代码的默认构建配置。对于所有遵循MD-SAL开发的模块(bundle)的构建,只需要继承这个pom,然后在你的pom中添加模块的自身依赖即可。
不仅是对parent pom的设计,包括各子项目中版本号规划,社区都给出了指导性建议,列在下面供读者参考:

  • 统一定义全局的parent pom,对所有子项目提供公共配置。
  • 除非必要,否则每个子项目只能有一个parent。
  • 所有子项目的parent都继承自全局parent pom。
  • 每个子项目中的模块的版本号要统一,版本号要按照..格式进行定义。
  • 项目依赖的版本号在parent pom里统一进行管理,在子项目的模块pom里不能对版本号硬编码。
  • 要对所有子项目使用一致的命名规范。

ODL的命名规范包括代码目录命名、模块坐标的命名规范、feature的命名规范。这里就不再详细说明了,如果想进一步详细了解的可以参考:https://wiki.opendaylight.org/view/CrossProject:HouseKeeping_Best_Practices_Group:Project_layouthttps://wiki.opendaylight.org/view/CrossProject:Integration_Group:About_User_Facing_Features
图2-1是按照odlparent项目发布的最新版本设计的parent pom继承关系示意图。
image.png

图2-1 odlparent中父pom设计

在图2-1中,各pom的说明简单如下:

  • odlparent-lite—最基础的父pom,被所有的ODL项目的Maven模块直接或者间接继承。可以供不生成发布坐标(artifacts)的Maven模块直接继承(比如聚合的POM)。
  • odlparent—公共的父pom,供包含Java代码的Maven模块继承。
  • bundle-parent—供生成OSGi Bundle的Maven模块继承的父pom。
  • binding-parent—遵循MD-SAL架构设计的Maven模块继承的父pom。
  • single-feature-parent—供生成单个Karaf 4 feature的Maven模块继承的父pom。
  • feature-repo-parent—供生成Karaf 4 feature库的Maven模块继承的父pom。
  • features-odlparent—ODL依赖的公共库的feature集合的库。
  • karaf4-parent—供生成Karaf 4发布包的Maven模块所继承的父pom。

图2-1中虚框内的两个pom(dom-parent和binding-parent)不是在odlparent项目里定义的,而是在mdsal项目里定义的。
以上parent pom的详细说明以及在子项目中的继承应用参见2.3节和2.4节。

2.3 实现详解

本节我们将对图2-1中pom文件的设计,主要是对pom包含的配置以及主要用途进行详细说明。

2.3.1 基础parent设计

最基础的parent pom包括两个—odlparent-lite和odlparent,前者包括一些公共配置信息,后者则在前者的基础上增加了通用的第三方库的依赖。
1. odlparent-lite
odlparent-lite是ODL所有的Maven项目和模块最基础的父pom,主要提供了以下公共配置信息。

  • license information(许可证信息)。
  • organization information(组织信息)。
  • issue management information (a link to our Bugzilla)(问题管理)。
  • continuous integration information (a link to our Jenkins - setup)(持续集成信息,Jenkins的链接)。
  • default Maven plugins (maven-clean-plugin, maven-deploy-plugin, maven-install-plugin, maven-javadoc-plugin with HelpMojo support, maven-project-info-reports-plugin, maven-site-plugin with Asciidoc support, jdepend-maven-plugin)(默认的Maven插件)。
  • distribution management information(发布管理信息)。
  • source code management(源码管理)。

pom中的具体配置如代码清单2-1所示。
代码清单2-1 odlparent-lite中的公共配置信息
image.png
image.png
ODL的问题跟踪现已改为JIRA(https://jira.opendaylight.org/),原来的Bugzilla虽然还可以访问,但已不能在Bugzilla上提交Bug。
另外,在这个pom中还定义了几个有用的profile,以满足不同的环境或不同的构建要求。举一个例子,如代码清单2-2所示的这个profile。
代码清单2-2 odlparent-lite中的快速构建的profile
image.png
使用该profile,只需要在执行构建命令时,加上参数-Pq(即mvn clean install -Pq),即可跳过测试、忽略代码检查、不生成site和文档等,加速构建的过程。
这个pom可直接被ODL子项目中聚合的pom所继承。
2. odlparent
该pom继承自odlparent-lite,主要提供ODL项目的依赖和插件管理。
如果ODL的项目或你自己写的模块依赖到如下第三方库,就需要继承odlparent这个pom。

  • Akka (and Scala)
  • Apache Commons:

    • commons-codec
    • commons-fileupload
    • commons-io
    • commons-lang
    • commons-lang3
    • commons-net
      Apache Shiro
  • Guava
  • JAX-RS with Jersey
  • JSON processing:

    • GSON
    • Jackson
  • Logging:

    • Logback
    • SLF4J
  • Netty
  • OSGi:

    • Apache Felix
    • core OSGi dependencies (core,compendium…)
  • Testing:

    • Hamcrest
    • JSON assert
    • JUnit
    • Mockito
    • Pax Exam
    • PowerMock
  • XML/XSL:

    • Xerces
    • XML APIs

因为ODL所依赖的第三方库是动态的,可能会增加或删去某个第三方库依赖,所以这个列表不一定是完整准确的。
这个pom还配置了对Java源码的Checkstyle规则设置,特别的是对于所有Java代码,其强制必须附带EPL License的声明头。声明头格式要求如代码清单2-3所示。

代码清单2-3 EPL license header

image.png
其中,${year}是代码发布年份,${holder}是发布该代码的版权所有者。

2.3.2 模块构建

ODL的模块遵循OSGi规范,在OSGi中,模块即bundle。因此,构建ODL项目中的某个模块,即编译构建OSGi的bundle。另外,ODL的核心框架是MD-SAL,由于YANG模型是贯穿模块设计的,且其是模块交互的基础,因此,以YANG模型驱动的模块设计是ODL中普适的设计模式,所以构建包含YANG模型的模块就成了ODL各子项目的公共需求。
1. bundle-parent
该pom继承自odlparent,这个pom主要用来配置OSGi bundle的构建。在该pom中:

  • maven-javadoc-plugin被激活,用以构建Javadoc的JAR包。
  • maven-source-plugin被激活,用以构建源码的JAR包。
  • maven-bundle-plugin被激活(包括扩展),用以构建OSGi bundles(使用“bundle”类型打包)。

另外,在该pom中也增加了JUnit作为test范围的默认依赖,因此在bundle的编译构建过程中,默认是会执行单元测试的。
2. dom-parent
这个pom不是在odlparent中定义的模块,而是在mdsal项目中。其继承自bundle-parent,在bundle-parent基础上只增加了对yangtools和mdsal的依赖管理(dependencyMan-agement)。
3. binding-parent
该pom继承自dom-parent,也是在子项目mdsal中定义的。该pom增加了通过yang-maven-plugin插件对YANG文件的解析及根据解析的YANG文件自动生成代码的配置。遵循MD-SAL框架设计的模块pom都可以继承自该pom,生成的代码默认输出到target/ generated-sources/mdsal-binding/,读者可以到这个目录下查看自动生成的代码。不过依据Maven的约定优于配置原则,不建议大家自行修改这个默认配置。

2.3.3 feature组织

feature是Karaf中引入的一个概念,通常是若干相关的bundle及其配置的集合。安装这个feature的时候,相应的bundle也会被安装上去。通过feature,极大地方便了Karaf中对于bundle的管理。在ODL中,每个子项目的功能特性的发布也是按照feature发布的。
1. single-feature-parent
该pom继承自odlparent,用以生成Karaf 4的features:

  • karaf-maven-plugin被激活,用以构建Karaf features,即以“feature”类型打包的pom(“kar”类型也支持)。
  • 基于pom中定义的依赖生成feature.xml文件,你也可以通过配置src/main/feature/feature.xml文件来实现对feature.xml的初始化。
  • Karaf feature在构建完成后会被测试,以确保这些feature能在Karaf容器里安装激活。

在生成feature.xml过程中,传递依赖默认会被添加,这样,我们只需要在pom中定义最重要的直接依赖即可,其他的依赖会自动查找。
配置文件“configfiles”既要在pom中定义依赖,也要作为feature.xml的元素定义。feature依赖的feature需要被定义为“xml”类型和“features”类别,具体配置可参考代码清单2-4和代码清单2-5。

代码清单2-4 pom中feature依赖配置及configfile依赖配置

image.png

代码清单2-5 feature.xml文件中configfile标签配置

image.png
2. feature-repo-parent
该pom继承自odlparent,用以构建Karaf 4的feature库,且与single-feature-parent遵循同样的设计原则,其是为feature库专门设计的,它会把pom中的所有依赖的feature构建为一个feature库,并在构建过程中提供对feature的测试支持。
3. features-odlparent
这是一个包含了ODL依赖的基础feature库的pom,包括Karaf自带的feature,如jdbc、jetty、war、feature等,也包括ODL依赖的其他第三方库的feature,比如akka、guava、netty、lmax、triedmap、jersey、javassist、gson、jackson、apache-commons等。

2.3.4 版本打包

1. karaf-plugin
ODL社区设计了一个Maven插件karaf-plugin,用来实现把所有依赖的组件发布到本地仓库的目的,其基本实现原理是根据打包的feature列表把其中所有依赖的bundle和配置都复制到本地仓库。插件源码实现不太复杂,感兴趣的读者可以直接下载odlparent项目阅读。
2. karaf4-parent
该pom用于构建Karaf 4的发布包,这个pom里用到了karaf-plugin这个插件,其会把所有运行时依赖的feature依赖都打包在这个发布包中,依赖的组件会被复制到发布包的system目录下,该目录的默认配置为Karaf的本地仓库。pom文件中的属性karaf.local-Feature用来指定初始启动的feature(除了standard外的feature)。
构建的发布包可用于本地测试。

2.4 项目模板

2.4.1 项目目录布局设计

按照前面的pom层次设计及规范要求,一个典型的ODL子项目目录布局可设计如下:
image.png
image.png
ODL子项目或者你自己定义的项目一般都包含多个模块,为了方便处理,在上面的目录布局中,api和impl可以一起放在一个单独的目录中。比如module1,如果增加一个模块,那么就再增加一个子目录module2,里面仍然可以按照api和impl的结构布局,api和impl这两个目录名字也可以按照实际情况重新命名。
对于聚合的pom或者集成测试模块,我们一般是不需要发布该pom和模块的,如果我们不想发布pom和模块,可在pom文件里加上如代码清单2-6所示的配置。

代码清单2-6 不准备发布的pom配置

image.png

2.4.2 ODL模板项目

Maven中有一个概念叫achetype(原型),也可称之为项目模板,学会了上文的项目目录规划和布局,我们就可以设计一个Maven的模板项目(pom中打包发布类型为maven-achetype),后续如果我们想创建具有类似目录结构的项目,可以直接通过Maven的命令mvn archetype:generate创建该模板生成项目骨架,然后直接基于这个骨架把我们自己开发的代码添加进去。
其实,Maven archetype项目在ODL最初发布的几个版本中就已经有了,不过这个项目原来是属于controller子项目的一部分,并且其提供的项目原型的目录结构和继承的pom也在一直调整。不过从氟版本(第9个发布版本)开始,原型项目就被独立出来,单独成立了一个achetypes项目,这样方便对原型项目的测试和发布。当前这个项目只包括一个opendaylight-startup项目原型,但并没有在氟版本中正式发布,如果读者想基于这个原型来创建基于ODL氟版本的自定义项目,可以考虑使用SNAPSHOP版本,通过下载achetypes源码,在本地构建安装这个项目,这样就可以在本地使用了。

2.5 本章小结

ODL的项目管理用到的工具和基础设施除了Maven,其他还有JIRA、Jenkins、Nexus等,因为其他工具与我们关注的项目源代码本身关系不大,所以就不介绍了。本章主要介绍了ODL利用Maven这个项目管理工具,不断地对自身进行优化和演进,逐步梳理清楚ODL中的项目间的层次结构关系,使其越来越合理,越来越容易被理解和掌握。
ODL从碳版本到氮版本,完成了Karaf 3到Karaf 4的升级,虽扯非常广,但由于对于ODL的所有项目的配置和依赖做到了通过odlparent统一管理,使得项目的构建配置和依赖配置设计十分清晰合理。因此,本次升级只跨了一个版本就完成了,这也验证了ODL社区在项目管理领域的不断成熟。
社区也曾经讨论过用Gradle取代Maven作为项目管理的工具,但并未确定是否会真的实施,目前看可能性不大。就算真的把Maven迁移为Gradle,读者也无须担心,变化总是会向好的方面发展。其实无论是ODL的项目管理,还是ODL的基础架构,都是处于一个持续发展的过程中,静止不变的开源项目是没有活力的。我们在理解ODL的基础架构时,也要时刻注意这一点,ODL的基础架构也是逐步演进才达到目前的状态的,并且还处于不断向前的过程中,我们要以动态的眼光看待ODL,这才是正确的态度。接下来我们将基于前面介绍的基础知识,聚焦ODL核心项目模块的设计原理和实现源码,让读者对ODL当前最新版本中的核心框架和实现原理有一个详尽的了解。

相关文章
|
3月前
|
人工智能 监控 数据挖掘
数字化转型中的项目管理架构:创新与挑战
【8月更文第7天】简述数字化转型对企业的重要性及其对项目管理带来的影响。 - 概述数字化转型下项目管理架构所面临的机遇与挑战。
359 0
|
3月前
|
敏捷开发 架构师 数据可视化
利用敏捷与精益原则:项目管理架构师的实践指南
【8月更文第7天】在快速变化的商业环境中,项目管理架构师面临着前所未有的挑战。传统的瀑布式项目管理方法已经难以适应不断变化的需求。敏捷开发方法和精益思维为解决这些问题提供了强大的工具。本文将探讨项目管理架构师如何运用敏捷与精益原则来提高项目的灵活性、效率和质量。
106 0
|
3月前
|
监控 架构师 项目管理
项目管理架构师的角色与职责:构建高效项目交付框架
【8月更文第7天】在当今快速变化的商业环境中,组织需要灵活高效的项目交付机制来应对不断出现的新挑战。项目管理架构师(Project Management Architect, PMA)作为一种新兴的角色,在确保项目成功交付方面扮演着至关重要的角色。本文将探讨PMA的核心职责,以及他们如何通过设计和实施项目管理流程来提高项目的可扩展性和适应性,并通过有效的项目治理来提升团队的整体表现。
163 0
|
4月前
|
缓存 项目管理
项目管理定义问题之DDD架构的分层架构中基础层作用是什么
项目管理定义问题之DDD架构的分层架构中基础层作用是什么
|
Java 项目管理
艾伟也谈项目管理,软件架构引言之项目管理的问题
  软件架构引言之项目管理的问题     很多朋友都有过或者正在管理一个或者多个软件项目,那么我的文章就从这个问题开始:如果单纯从表象来说,软件项目管理过程中暴露的最大问题是什么?     不同的人的会有不同的答案,但是大致这样的答案我想大部分人都是会认可的,那就是“进度拖延”。
1118 0
|
存储 架构师 项目管理
艾伟也谈项目管理,五年Skype架构师之路的感言
  简介   作为架构师和设计者,我们常把手头的事情作为工作焦点,很少反思过去如何。我们应该温故而知新。我从作为skype架构组领导的55 个月经历中总结了6个经验。其中一些是技术性的,另外一些是架构师较为软性的观点。
1160 0
|
架构师 项目管理
艾伟也谈项目管理,软件架构师之职责范围
  由于国内外软件土壤差别巨大,适合国外的一些理论在国内不一定行的通,而国内的一些资料往往都是根据国外的资料直接搬过来用的,这也直接导致国外的软件架构师在国内变得水土不服。今天本篇随笔的内容则是在一些培训资料的基础上,加上自己的思考,总结出来的适合国情的软件架构师职责范围。
1203 0
|
架构师 测试技术 项目管理
艾伟也谈项目管理,给敏捷团队中的架构师的10个建议
  微软澳大利亚的解决方案架构师Tom Hollander,在TechEd Australia大会上举行了一场题为“敏捷团队中的架构师角色”的演讲。在演讲中,他讨论了他作为领导敏捷团队的架构师所做的工作。
1153 0
|
架构师 项目管理
艾伟也谈项目管理,架构组织管理
  架构组织管理的五大原则:构想、节奏、预见、协作和简化   架构组织的三在概念:准则、模式和反模式   准则:为了把原则运用到实践中,需要实施细节。准则把广泛的原则翻译成是否和如何执行原则的细节。   模式:描述了开发或者使用软件架构时可能遇到的常见问题的解决方案。
1284 0
|
项目管理 定位技术 数据可视化