带你读《Python网络编程(原书第2版)》之三:API和意图驱动网络-阿里云开发者社区

开发者社区> 华章出版社> 正文

带你读《Python网络编程(原书第2版)》之三:API和意图驱动网络

简介: 本书是一本实用型的基础技术实践工具书,技术性较强,如果你想快速了解计算机网络管理、网络安全、自动化运维、Python Web搭建、网络测试相关的知识,本书很适合你。本书涵盖的知识点主要是网络运维相关技术,在学习完所有的章节之后,读者能对网络的管理有初步的了解。每个章节的后面部分都是有一定难度的扩展资源,循序渐进,帮助读者提升网络运维能力。

点击查看第一章
点击查看第二章

第3章

API和意图驱动网络
在第2章中,我们研究了使用Pexpect和Paramiko的网络设备进行交互的方式。这两个工具都使用持久会话模拟用户输入命令,就好像他们自己坐在终端前面一样。在某种程度上这起了很大的作用。因此,这使得在设备上执行发出的命令和捕获输出变得足够简单。然而,当输出超过数行字符时,使用计算机程序来解释输出就变得困难了。Pexpect和Paramiko的返回输出是一系列旨在被人类阅读的字符。输出的结构由行和空白组成,这些行和空白对人类是友好的但很难被计算机程序理解。
为了使我们的计算机程序能够自动执行我们想要执行的许多任务,我们需要解释返回的结果并根据返回的结果进行后续操作。当我们无法准确且可预测地解释返回的结果时,我们无法自信地执行下一个命令。
幸运的是,这个问题已经被互联网社区解决了。想象一下计算机和人类在他们同时阅读一个网页时的区别。人类看到的是浏览器解释的文字、图片和空白;计算机可以看到原始HTML代码、Unicode字符和二进制文件。当网站需要成为另一台计算机的Web服务时会发生什么?相同的Web资源需要适应人类客户和其他计算机程序。这个问题听起来不像我们之前介绍过的吗?答案就是应用程序接口(API)。值得注意的是,根据维基百科,API是一个概念,而不是特定的技术或框架。
在计算机编程中,应用程序编程接口(API)是一组用于构建应用程序软件的子例程定义、协议和工具。一般而言,它是一组定义明确的用于不同软件组件间通信的方法。一个好的API可以通过提供所有构建块来更容易地开发计算机程序,然后由程序员将它们组合在一起。
在我们的用例中,一组明确定义的通信方法将在我们的Python程序和目标设备之间。网络设备的API为计算机程序提供单独的接口。确切的API实现是特定于供应商的。一个供应商可能更喜欢基于JSON的XML,一些可能提供HTTPS作为底层传输协议,而另一些供应商可能提供Python库作为包装器。尽管存在差异,但API的概念仍然相同:它是针对其他计算机程序优化的独立通信方法。
在本章中,我们将会看到下面几个主题:

  • 将基础设施视作代码、意图驱动网络和数据建模。
  • Cisco NX-API和以应用程序为中心的基础设施。
  • Juniper NETCONF和PyEZ。
  • Arista eAPI和PyEAPI。

3.1 基础设施作为代码

在一个完美的世界中,设计和管理网络的网络工程师和架构师应该专注于他们希望网络实现的目标,而不是设备级别的交互。在我作为本地ISP实习生的第一份工作中,我的第一个任务是在客户的网站上安装路由器以打开他们的部分帧中继链路(还记得吗?)。我该怎么办?我问。接着我接到了一个标准的操作程序,用于打开帧中继链路。我去了客户现场,盲目地输入了命令,看着绿灯闪烁,然后高高兴兴地收拾好行李,拍了拍自己的背部,做得很好。和第一次任务一样令人兴奋的是,我并不完全理解我在做什么。我只是按照说明而不考虑我输入的命令的含义。如果灯是红色而不是绿色,我将如何排除故障呢?我想我会打电话给办公室求救。
当然,网络工程不是要在设备中输入命令,而是建立一种方法,允许服务以尽可能少的摩擦从一个点传递到另一个点。我们必须使用的命令和我们必须解释的输出仅仅意味着结束。换句话说,我们应该关注我们对网络的意图。我们希望网络实现的目标远比用来使设备完成我们希望它做的事情的命令语法更重要。如果我们进一步提取将我们的意图描述为代码行的想法,我们可以将整个基础设施描述为特定状态。在使用必要的软件或框架来强制执行该状态的情况下,以代码来描述基础结构。

3.1.1 意图驱动网络

自本书第1版出版以来,在主要网络供应商选用基于意图的网络这一术语来描述下一代设备之后,该术语的使用量有所增加。在我看来,意图驱动网络是定义一种状态的方法并且网络应该拥有软件代码来强制执行该状态。例如,如果我的目标是阻止外界访问80端口,那就是我应该如何将其声明为网络的意图。底层软件将负责了解在边界路由器上配置和应用必要的访问列表的语法,以实现该目标。当然,意图驱动网络是一个没有明确答案的想法。但是这个想法很简单明了,我认为应该把重点放在网络的意图上,并从设备级的交互中抽象出来。
在使用API时,我认为它使我们更接近意图驱动网络的状态。简而言之,因为我们对在目标设备上执行的特定命令的层进行抽象,我们专注于我们的意图而不是特定的命令。例如,回到我们的block port 80访问列表示例,我们可能在Cisco上使用访问列表和访问组,在Juniper上使用过滤器列表。但是,在使用API时,我们的程序可以开始询问执行程序的意图,同时屏蔽它们正在与之交谈的物理设备类型。我们甚至可以使用更高级别的声明性框架,例如Ansible,我们将在第4章中介绍。但就目前而言,让我们专注于网络API。

3.1.2 屏幕抓取与API结构化输出

假设有一个常见的场景,我们需要登录到网络设备,并确保设备上的所有接口都处于up/up状态(状态和协议都显示为up)。对于进入Cisco NX-OS设备的人工网络工程师来说,在终端上发出show IP interface brief命令就足够简单了,从输出的接口上就可以很容易地判断出哪个接口是打开的:
image.png

行分隔符、空白和列标题的第一行很容易用人眼区分开来。实际上,它们是用来帮助我们将每个接口的IP地址从第一行排到第二行和第三行。如果我们把自己放在计算机的位置上,所有这些空格和换行只会让我们远离真正重要的输出,即:哪些接口处于up/up状态?为了说明这一点,我们可以查看相同操作的Paramiko输出:
image.png

如果我们要解析这些数据,下面我将以伪代码的方式来表示我所做的事情(我将编写的代码的简化表示):

  1. 通过换行符分隔每一行。
  2. 我可能需要也可能不需要包含执行命令show ip interface brief的第一行。现在,我觉得我不需要它。
  3. 取出第二行的所有内容直到VRF,并将其保存在变量中,因为我们想知道输出显示哪个VRF。
  4. 对于其余的行,因为不知道有多少接口,我们将使用正则表达式语句来搜索该行是否以可能的接口(例如lo环回接口和Eth以太网接口)开始。
  5. 我们需要通过空白将这一行分成三个部分,每个部分由接口名称、IP地址和接口状态组成。
  6. 然后使用正斜杠(/)进一步将接口状态拆分为协议状态、链接状态和管理状态。
    这只是为人们可以直接了解的事情而做的大量工作! 你可能能够优化代码和行数,但一般来说这就是当我们需要筛选非结构化的东西时需要做的事情。这个方法有许多缺点,但以下是我能看到的一些更大的问题:
  • 可扩展性:在解析命令的细节上我们花了很多时间。很难想象如何才能启动我们通常运行的上百个命令。
  • 可预测性:实际上无法保证输出在不同的软件版本之间保持不变。 如果输出稍有改变,就可能让我们来之不易的信息收集之战变得毫无用处。
  • 供应商和软件锁定:也许最大的问题是,一旦我们费力解析了这个特定供应商和软件版本(比如Cisco NX-OS)的输出,我们需要为下一个挑选的供应商重复这个过程。我不了解你,但如果我要评估一个新的供应商,如果我必须重写所有屏幕代码,供应商则处于严重的入职劣势。

让我们将它与同一个show IP interface brief命令的NX-API调用的输出进行比较。我们在本章的后面部分将讨论从设备获取此输出的细节,重要的是将以下输出与以前的屏幕抓取输出进行比较:
image.png
image.png

NX-API可以返回XML或JSON格式的输出,这是我们需要的JSON输出。马上,你可以看到结构化输出,可以直接映射到Python字典数据结构。无须解析—你只需选择键并检索与键关联的值。你还可以从输出中看到输出中有各种元数据,例如命令的成功或失败。如果命令失败,会有一条消息告诉发送人失败的原因。你不再需要跟踪发出的命令,因为它在input字段中已经返回给你了。输出中还有其他有用的元数据,例如NX-API版本。
这种类型的转换使供应商和运营商的生活更加轻松。在供应商方面,他们可以轻松传输配置和状态信息。如果需要暴露额外的东西,他们可以用相同的数据结构来添加额外的内容域。在运营商方面,他们可以轻松地获取信息并围绕它构建基础设施。使用者们普遍认为自动化是非常需要的,也是一件好事。问题通常以自动化的格式和结构为中心。正如你将在后面章节看到的那样,API下有许多竞争技术。仅在传输方面,我们有REST API、NETCONF和RESTCONF等。最终,整体市场可能会决定未来的最终数据格式。与此同时,我们每个人都可以形成自己的意见,并推动行业向前发展。

3.1.3 基础设施的数据建模作为代码

根据维基百科(https://en.wikipedia.org/wiki/Data_model ),数据模型的定义如下:
数据模型是一种抽象模型,用于组织数据元素并标准化它们的相互关系及它们与现实世界实体的属性的关系。例如,一个数据模型可以指定表示汽车的数据元素由多个其他元素组成,这些其他元素代表汽车的颜色和大小并定义其所有者。
数据建模过程如下图所示:

image.png

应用于网络时,无论是数据中心,校园还是全球广域网,我们可以将此概念应用于我们描述的网络抽象模型。如果仔细查看物理数据中心,我们可以将第2层以太网交换机视为包含每个端口的MAC地址映射表的设备。我们的交换机数据模型描述了如何将MAC地址保存在表中,其中包括密钥、附加特性(考虑VLAN和专用VLAN)等。同样,不局限于设备,我们可以将整个数据中心映射到模型中。我们可以从每个访问层、分发层和核心层中的设备数量、它们如何连接以及它们在生产环境中的行为方式开始。例如,如果我们有一个fat-tree网络,每个主干路由器应该有多少链接,它们应该包含多少路由,以及每个前缀应该有多少个下一跳?这些特征被映射为我们应该经常检查的理想状态所引用的一种格式。
其中一种相对较新的网络数据建模语言Yet Another Next Generation(YANG)正在引起关注(尽管一般认为一些IETF工作组确实有幽默感)。它于2010年首次在RFC 6020中发布,并且随后在供应商和运营商中获得了关注。在撰写本文时,从供应商到平台,对YANG的支持差异很大。因此生产中的适应率相对较低。但是,这是一项值得关注的技术。

3.2 Cisco API和Cisco ACI

Cisco系统公司,网络领域的重量级公司,没有错过网络自动化的趋势。它在推动网络自动化方面取得了成功,它进行了各种内部开发、产品增强、合作伙伴关系建立以及许多外部收购。但是,产品线包括路由器、交换机、防火墙、服务器(统一计算)、无线、协作软件和硬件以及分析软件,仅举几例,很难知道从哪里开始。
由于本书侧重于Python和网络,我们将把这一部分作为主要网络产品。特别是,我们将涵盖以下内容:

  • 使用NX-API进行Nexus产品自动化。
  • Cisco NETCONF和YANG的示例。
  • Cisco以应用程序为中心的数据中心基础设施。
  • 面向企业的Cisco以应用程序为中心的基础设施。

对于此处的NX-API和NETCONF示例,我们可以在实验室设备上始终使用Cisco DevNet,也可以在本地运行Cisco VIRL。由于ACI是一个单独的产品并获得了对于以下ACI示例的物理交换机的许可,我建议使用DevNet实验了解这些工具。如果你是幸运的工程师之一,有一个你可以使用的私人ACI实验室,请随意使用它作为相关的示例。
我们将使用与第2章中所做的类似的实验拓扑,但运行nx-osv的设备除外:
我们来看看NX-API。

image.png

3.2.1 Cisco NX-API

Nexus是Cisco数据中心交换机的主要产品线。NX-API(http://www.cisco.com/c/en/us/td/docs/switches/datacenter/nexus9000/sw/6-x/programmability/guide/b_Cisco_Nexus_9000_Series_NXOS_Programmability_Guide/b_Cisco_Nexus_9000_SeriesNX-OS_Programmability_Guide_chapter_011.html )允许工程师与在设备外部的交换机通过各种传输(包括SSH,HTTP和HTTPS)进行交互。

3.2.1.1 实验软件安装和设备准备

以下是我们将安装的Ubuntu软件包。你可能已经有了一些pip和git这样的包:
image.png

提示:如果你使用的是Python 2,请改用以下软件包:sudo apt-get install -y python-dev libxml2-dev libxslt1-devlibffi-dev libssl-dev zlib1g-dev python-pip git python requests。
ncclient(https://github.com/ncclient/ncclient )库是一个Python库,用于NETCONF客户端。我们将从GitHub仓库安装它,以便我们可以安装最新版本:
image.png

Nexus设备上的NX-API默认关闭,因此我们需要将其打开。我们要么使用已创建的用户(如果你使用的是VIRL自动配置),要么创建一个NETCONF程序的新用户:
image.png

对于我们的实验,我们将打开HTTP和沙箱配置,因为它们在生产中应该是关闭的:
image.png

现在准备查看我们的第一个NX-API示例。

3.2.1.2 NX-API示例

NX-API沙箱是一种很好的使用各种命令、数据格式,甚至直接从网页上复制Python脚本的方式。在最后一步中,我们出于学习的目的打开了它。它应该在生产中关闭。让我们启动一个网络浏览器并根据我们已经熟悉的CLI命令查看各种消息格式、请求和响应:

image.png

在以下示例中,我为show version命令选择了JSON-RPC和CLI命令类型:

image.png

如果你不确定消息格式的可支持性,或者如果你对需要在你的代码中检索的值的响应数据字段键有疑问,沙箱会派上用场。
在我们的第一个例子中,我们只是连接到Nexus设备并打印出来首次建立连接时交换的功能:
image.png

主机、端口、用户名和密码的连接参数是非常明显的。设备参数指定客户端连接的设备类型。使用ncclient库时,我们将在Juniper NETCONF部分中看到不同的响应。hostkey_verify绕过SSH的known_host要求;如果没有,那么主机需要列在~/.ssh/known_hosts文件中。look_for_keys选项禁用公钥–私钥验证,但使用用户名和密码认证。
警告:如果你遇到https://github.com/paramiko/paramiko/issues/748 使用Python 3和Paramiko的问题,请随意使用Python 2。希望在你阅读本节时,问题已经解决。
输出将显示此版本NX-OS支持的XML和NETCONF功能:
image.png

在SSH上使用ncclient和NETCONF非常棒,因为它让我们更接近本机实现和语法。我们稍后将使用相同的库。对于NX-API,处理HTTPS和JSON-RPC可能更容易。在早期的NX-API Developer Sandbox截图中,在Request框中,有一个标记为Python的框。如果单击它,你将能够获得基于请求库的自动转换的Python脚本。
警告:以下脚本使用名为requests的外部Python库。它是一个非常流行的、自称为面向人类的HTTP库,被亚马逊、谷歌、NSA等公司使用。你可以找到有关它的更多信息,请访问官方网站(http://docs.python-requests.org/en/master/ )。
对于show version示例,将自动为你生成以下Python脚本。我粘贴在输出中而没有做任何修改:
image.png

在cisco_nxapi_2.py脚本中,你将看到我只修改了前面文件的URL、用户名和密码。输出被解析为仅包括软件版本。这里是输出:
image.png

使用此方法的最佳部分是相同的整体语法结构用于配置命令以及show命令。cisco_nxapi_3.py文件说明了这一点。对于多行配置,你可以使用ID字段指定操作顺序。在cisco_nxapi_4.py中,列出了以下有效内容以更改接口配置模式下接口Ethernet 2/12的描述:
image.png

我们可以通过查看Nexus设备的运行配置情况来验证上一个配置脚本的结果:
image.png
image.png

在下一节中,我们将查看Cisco NETCONF和YANG的一些示例模型。

3.2.2 Cisco和YANG模型

在本章的前面,我们讨论了使用数据建模语言YANG表示网络的可能性。我们再来看一些例子。
首先,我们应该知道,YANG模型只定义通过NETCONF协议发送的数据类型,而没有规定数据应该是什么。其次,值得指出的是,NETCONF是作为独立协议存在的,正如我们在NX-API部分看到的那样。相对较新的YANG在供应商和产品线之间的可移植性参差不齐。例如,如果我们运行以前用于运行IOS-XE的Cisco 1000v的功能交换脚本,我们将看到:
image.png

将其与我们看到的NX-OS的输出进行比较。显然,IOS-XE比NX-OS更支持YANG模型的特性。当支持全行业的网络数据建模时,它显然可以跨设备使用,这有利于网络自动化。但是,在我看来,由于供应商和产品的支持不均衡,它还不够成熟,不能完全用于生产网络。对于本书,我包含了一个名为cisco_yang_1.py的脚本。它展示了如何使用名为urn:ietf:params:xml:ns:yang:ietf-interfaces的YANG过滤器解析NETCONF XML的输出,作为查看现有标记覆盖的起点。
警告:你可以在YANG GitHub项目页面上查看最新的供应商支持
https://github.com/YangModels/yang/tree/master/vendor )。

3.2.3 Cisco ACI

Cisco应用程序中心基础设施(ACI)旨在为所有网络组件提供中心化的方法。在数据中心上下文中,它意味着集中控制器知道并管理机架交换机的主干、叶片和顶部,以及所有的网络服务功能。这可以通过GUI、CLI或API实现。一些人可能认为ACI是Cisco对更广泛的基于控制器的软件定义网络的回答。
ACI和APIC-EM之间的差异是ACI中比较令人困惑的一点。简而言之,ACI侧重于数据中心操作,而APIC-EM侧重于企业模块。两者都提供了对网络组件的集中视图和控制,但是它们都有自己的焦点和工具集的共享。例如,很少有大型数据中心面向客户的无线基础设施部署,但是无线网络是当今企业的关键部分。另一个例子是不同的网络安全方法。虽然安全在任何网络中都很重要,但是在数据中心环境中,为了可伸缩性,许多安全策略被推送到服务器上的边缘节点。在企业安全中,策略在网络设备和服务器之间共享。
与NETCONF RPC不同,ACI API遵循REST模型,使用HTTP动词(GET、POST、DELETE)指定需要的操作。
警告:我们可以看看cisco_apic_em_1.py文件,它是Cisco示例代码上的一个修改版本lab2-1-get-network-device-list.py (https://github.com/CiscoDevNet/apicem-1.3-LL-sample-codes/blob/master/basic-labs/lab2-1-get-network-device-list.py )。
以下部分列出了不带注释和空格的缩略版本。
第一个名为getTicket()的函数在控制器上使用HTTPS POST,其路径为/api/v1/ticket,头部嵌入用户名和密码。此函数将返回解析后的响应作为凭证,它仅在有限的时间内有效:
image.png

然后,第二个函数调用另一个路径/api/v1/network-devices,将新获得的票据嵌入到头部中,然后解析结果:
image.png

这是一个非常常见的API交互工作流。客户端将在第一个请求中使用服务器进行身份验证,并接收一个基于时间的令牌。此令牌将在后续请求中使用,并作为身份验证的证明。
输出同时显示了原始JSON响应输出和解析表。对DevNet实验控制器执行时的部分输出如下所示:
image.png
image.png

如你所见,我们只查询单个控制器设备,但是我们能够获得控制器所知道的所有网络设备的高级视图。在我们的输出中,Catalyst 2960-C交换机、3500 Access Points、4400 ISR路由器和5500 Wireless Controller都可以进一步研究。当然,缺点是ACI控制器目前只支持Cisco设备。

3.3 Juniper网络的Python API

Juniper网络一直是服务提供商的宠儿。如果我们回头看一下垂直的服务提供商,就会发现自动化网络设备是其首要需求。在运级别数据中心出现之前,服务提供商拥有最多的网络设备。一个典型的企业网络可能在公司总部有一些冗余的互联网连接,使用服务提供商的私有MPLS网络将一些轮辐式远程站点连接回总部。对于服务提供商,它们需要构建、提供、管理和故障排除连接和底层网络。它们通过出售带宽和增值的托管服务来赚钱。对于服务提供商来说,投资于自动化以用最少的工程时间来保持网络的运转是有意义的。在它们的用例中,网络自动化是它们竞争优势的关键。
在我看来,服务提供商的网络需求与云数据中心之间的区别在于,传统上,服务提供商将更多的服务聚合到一个设备中。一个很好的例子是多协议标签交换(MPLS),几乎所有主要的服务提供商都提供这种交换,但是很少在企业或数据中心网络中使用。Juniper,作为一个非常成功的公司,已经发现了这一需求,并擅长于满足自动化服务提供商的需求。让我们看看Juniper的一些自动化API。

3.3.1 Juniper和NETCONF

网络配置协议(NETCONF)是一种IETF标准,2006年首次发布为RFC 4741,后来在RFC 6241中进行了修订。Juniper网络对这两个RFC标准都做出了重大贡献。事实上,Juniper是RFC 4741的唯一作者。Juniper设备完全支持NETCONF是有道理的,它是大多数自动化工具和框架的底层。NETCONF的一些主要特征包括:

  1. 它使用可扩展标记语言(XML)进行数据编码。
  2. 它使用远程过程调用(RPC),因此在HTTP(s)作为传输的情况下,URL端点是相同的,而预期的操作是在请求体中指定的。
  3. 它从上到下是基于层的概念。这些层包括内容、操作、消息和传输:

    image.png

Juniper网络在它的技术库里提供了一个广泛的NETCONF XML管理协议开发指南(https://www.juniper.net/techpubs/en_US/junos13.2/information-products/pathway-pages/netconf-guide/netconf.html#overview )。让我们看一下它的用法。

3.3.1.1 设备准备

为了开始使用NETCONF,让我们创建一个单独的用户,并打开所需的服务:
image.png

警告:对于Juniper设备实验,我使用的是一个较老的、不受支持的平台,名为Juniper Olive。仅供实验使用。你可以用你最喜欢的搜索引擎找到一些关于Juniper Olive的有趣的事实和历史。
在Juniper设备上,你总是可以以平面文件或XML格式查看配置。当你需要指定一行命令来进行配置更改时,平面文件非常有用:
image.png

当你需要查看配置的XML结构时,XML格式非常有用:
image.png

我们已经在Cisco部分安装了必要的Linux库和ncclient Python库。如果你还没有这样做,请参阅该部分并安装必要的包。
现在,我们准备看第一个Juniper NETCONF示例。

3.3.1.2 Juniper NETCONF示例

我们将使用一个非常简单的示例来执行show version。我们将这个文件命名为junos_netcon_1.py:
image.png

除了device_params之外,脚本中的所有字段都应该是非常容易理解的。从ncclient 0.4.1开始,添加了设备处理程序来指定不同的供应商或平台。例如,名称可以是juniper、CSR、Nexus或华为。我们还添加了hostkey_verify=False,因为我们使用的是Juniper设备的自签名证书。
返回的输出是用XML编码的rpc-reply,并带有一个output元素:
image.png
image.png

我们可以将XML输出解析为只包含输出文本:
image.png

在junos_netconf_2.py中,我们将对设备进行配置更改。我们将从一些新的导入开始,以构建新的XML元素和连接管理对象:
image.png

我们将锁定配置并进行配置更改:
image.png

在构建配置部分中,我们使用host-name和domain-name的子元素创建了一个新的system元素。如果你想知道层次结构,可以从XML显示中看到,system的节点结构是host-name和domain-name的父节点:
image.png

构建配置之后,脚本将增加配置并提交配置更改。以下是Juniper配置更改的常规最佳实践步骤(锁、配置、解锁、提交):
image.png
image.png

总的来说,NETCONF步骤很好地映射到你在CLI步骤中应该做的事情。请查看junos_netcon_3.py脚本,以获得更多可重用代码。下面的示例将一些逐步完成的例子与一些Python函数结合起来:
image.png

这个文件可以自己执行,也可以导入以供其他Python脚本使用。
Juniper还提供了一个Python库,用于它们的设备PyEZ。在下一节中,我们将查看一些使用该库的示例。

3.3.2 开发者的Juniper PyEZ

PyEZ是一个高级Python实现,可以更好地与现有Python代码集成。通过使用Python API,你可以在不了解Junos CLI的情况下执行常见操作和配置任务。
提示:Juniper在https://www.juniper.net/techpubs/en_US/junos-pyez1.0/information-products/pathway-pages/junos-pyez-developer-guide.html#configuration 的技术库中维护了一个全面的Junos PyEZ开发指南。如果你对使用PyEZ感兴趣,我强烈建议你至少浏览一下指南中的各个主题。

3.3.2.1 安装和准备

在安装Junos PyEZ时可以找到每个操作系统的安装说明页面(https://www.juniper.net/techpubs/en_US/junos-pyez1.0/topics/task/installation/junos-pyez-server-installing.html )我们将展示Ubuntu 16.04的安装说明。
以下是一些依赖包,由于运行之前的示例其中许多包应该已经在主机上了:
image.png

PyEZ包可以通过pip安装。在这里,我为python 3和Python 2安装:
image.png

在Juniper设备上,NETCONF需要配置为PyEZ的底层XML API:
image.png

对于用户身份验证,我们可以使用密码身份验证或SSH密钥对。创建本地用户很简单:
image.png

对于ssh密钥身份验证,首先在主机上生成密钥对:
image.png

默认情况下,公钥名为id_rsa.pub。公匙在~/.ssh/之下,而私钥将在同一个目录下命名为id_rsa。将私钥视为你永远不会分享的密码。公钥可以自由分发。在我们的用例中,我们将公钥移到/tmp目录,并启用Python 3 HTTP服务器模块创建一个可访问的URL:
image.png

提示:对于Python 2,使用python -m SimpleHTTPServer代替。
在Juniper设备上,我们可以通过从python 3 Web服务器下载公钥来创建用户并关联公钥:
image.png

现在,如果我们尝试使用管理站的私钥ssh,用户将自动验证:
image.png

让我们确保这两种身份验证方法都与PyEZ一起工作。让我们试试用户名和密码组合:
image.png
image.png

我们还可以尝试使用SSH密钥身份验证:
image.png

太棒了!现在我们准备看一些PyEZ的示例。

3.3.2.2 PyEZ示例

在前面的交互提示中,我们已经看到,当设备连接时,对象自动检索关于设备的一些事实。在我们的第一个示例junos_pyez_1.py中,我们连接到设备,对show interface em1执行RPC调用:
image.png

设备类具有rpc属性,该属性包含所有操作命令。这非常棒,因为我们在CLI中所能做的事情相较于API没有下滑。问题是我们需要找到xml rpc元素标记。在第一个示例中,我们如何知道show interface em1等于get_interface_information?我们有三种方法可以找到此信息:

  1. 我们可以引用供开发人员参考的Junos XML API。
  2. 我们可以使用CLI并显示等效的XML RPC,并将单词之间的短横线(-)替换为下划线(_)。
  3. 我们还可以通过使用PyEZ库以编程的方式实现这一点。
    我通常使用第二个选项直接获得输出:

image.png

这里有一个使用PyEZ编程的示例(第三个选项):
image.png

当然,我们还需要更改配置。在junos_pyez_2.py配置示例中,我们将从PyEZ导入一个额外的Config()方法:
image.png

我们将使用相同的块连接到一个设备:
image.png

new Config()方法将加载XML数据并进行配置更改:
image.png
image.png

PyEZ示例的设计非常简单。希望它们能够展示如何利用PyEZ满足Junos自动化的需求。

3.4 Arista Python API

Arista网络一直致力于大规模的数据中心网络。在公司简介页面(https://www.arista.com/en/company/company-overview)这样描述它:
“Arista网络建立的目的是为大型数据中心存储和计算环境提供软件驱动的云网络解决方案。”
请注意,该声明特别提到了大型数据中心,我们已经知道这些数据中心由服务器、数据库和网络设备组成。自动化一直是Arista的主要特性之一,这是有道理的。事实上,Linux背后支持它们的操作系统,允许许多附加的好处,比如Linux命令和内置的Python解释器。
与其他供应商一样,你可以通过eAPI直接与Arista设备交互,也可以选择利用它们的Python库。我们将看到两者的例子。在后面的章节中,我们还将讨论Arista与Ansible框架的集成。

3.4.1 Arista eAPI管理

Arista的eAPI是在几年前在EOS 4.12中首次引入的。它通过HTTP或HTTPS传输显示或配置命令列表,并以JSON响应。一个重要的区别是,它是远程过程调用(RPC)和JSON-RPC,而不是通过HTTP或HTTPS服务的纯RESTFul API。对于我们的意图和目的,区别在于我们使用相同的HTTP方法(POST)向相同的URL端点发出请求。我们不使用HTTP动词(GET、POST、PUT、DELETE)来表示我们的操作,而是在请求体中声明我们想要的操作。对于eAPI,我们将为我们的意图指定一个具有runCmds值的method键。
对于以下示例,我使用的是运行EOS 4.16的Arista物理交换机。

3.4.1.1 eAPI准备

在默认情况下,Arista设备上的eAPI代理是被禁用的,因此在设备上,需要在使用它之前启用它:
image.png

正如所见,我们已关闭HTTP服务器,而是使用HTTPS作为唯一的传输。从几个EOS版本之前开始,管理接口默认置于名为management的VRF中。在我的拓扑中,我通过管理界面访问设备,因此,我已经为eAPI管理指定了VRF。你可以通过“show management api http-commands”命令检查API管理状态:
image.png

启用代理后,你可以通过转到设备的IP地址来访问eAPI的探索页面。如果你更改了默认端口以进行访问,则只需将其附加到最后。身份验证与交换机上的身份验证方法相关联。我们将使用设备上本地配置的用户名和密码。默认情况下,将使用自签名证书:

image.png

你将进入一个资源管理器页面,你可以在其中键入CLI命令,并为你的请求正文获取一个不错的输出。例如,如果我想看看如何为show version创建一个请求体,这是我将在资源管理器中看到的输出:

image.png

概述链接将带你到示例使用和背景信息,而命令文档将作为show命令的参考点。每个命令引用都将包含返回值的字段名称、类型和简要说明。来自Arista的在线参考脚本使用jsonrpclib(https://github.com/joshmarshall/jsonrpclib/ ),这是我们将使用的。但是,截至编写本书时,它依赖于Python 2.6+并且还没有移植到Python 3,因此,在这些示例中我们将使用Python 2.7。
提示:当你阅读本书时,可能会有更新的状态。请阅读GitHub拉取请求(https://github.com/joshmarshall/jsonrpclib/issues/38)和GitHub README文件(https://github.com/joshmarshall/jsonrpclib/ )获取最新状态。
使用easy_install或pip直接安装:
image.png

3.4.1.2 eAPI示例

然后我们可以编写一个名为eapi_1.py的简单程序来查看响应文本:
image.png

请注意,由于这是Python 2,在脚本中,我使用了from__future__import print_function使未来的迁移变得更容易。与ssl相关的行适用于2.7.9之后的Python版本。欲获得更多信息,请参阅https://www.python.org/dev/peps/pep-0476/
这是我从之前的runCms()方法收到的响应:
image.png

如你所见,结果是包含一个字典项的列表。如果我们需要获取序列号,我们可以简单地引用项目编号和密钥:
image.png

输出将仅包含序列号:
image.png

为了熟悉命令参考,我建议你点击eAPI页面上的Command Documentation链接,并将你的输出与文档中show version的输出进行比较。
如前所述,与REST不同,JSON-RPC客户端使用相同的URL端点来调用服务器资源。你可以从前面的示例中看到runCmds()方法包含命令列表。要执行配置命令,可以遵循相同的框架,并通过命令列表配置设备。
以下是名为eapi_2.py的配置命令示例。在示例中,我们编写了一个函数,它将switch对象和命令列表作为属性:
image.png
image.png

以下是命令执行的输出:
image.png

现在,快速检查交换机以验证命令的执行:
image.png

总的来说,eAPI非常简单易用。大多数编程语言都有类似jsonrpclib的库,它们抽象出JSON-RPC内部。通过一些命令,你可以开始将Arista EOS自动化集成到你的网络中。

3.4.2 Arista Pyeapi库

Python客户端Pyeapi(http://pyeapi.readthedocs.io/en/master/index.html )库是eAPI的原生Python库包装器。它提供了一组绑定来配置Arista EOS节点。当我们已经拥有eAPI时,为什么我们需要Pyeapi呢?如果你在Python环境中,Pyeapi与eAPI之间的挑选主要是通过主观判断。
但是,如果你处于非Python环境中,那么eAPI可能就是你的选择。从我们的示例中,你可以看到eAPI的唯一要求是支持JSON-RPC的客户端。因此,它与大多数编程语言兼容。当我第一次使用时,Perl是脚本和网络自动化的主要语言。仍有许多企业依赖Perl脚本作为主要的自动化工具。如果公司已投入大量资源并且代码库使用的语言不是Python,使用JSON-RPC的eAPI将是一个不错的选择。
但是,对于我们这些喜欢使用Python编写代码的人来说,原生Python库在编写代码时意味着更自然的感觉。它当然使扩展Python程序更容易支持EOS节点。它还使得更容易跟上Python的最新变化。例如,我们可以使用Python 3和Pyeapi!
警告:在编写本书时,官方宣称Python 3(3.4+)的支持正在进行中,如文档(http://pyeapi.readthedocs.io/en/master/requirements.html )中所述。请查看文档以获取更多详细信息。

3.4.2.1 Pyeapi安装

使用pip安装很简单:
image.png

警告:请注意,pip还将安装netaddr库,因为它是Pyeapi规定的要求(http://pyeapi.readthedocs.io/en/master/requirements.html )的一部分。
默认情况下,Pyeapi客户端将在你的主目录中查找名为eapi.conf的隐藏(前面有句点)INI样式文件。你可以通过指定eapi.conf文件路径来覆盖此行为,但通常最好将连接凭据分开并将其从脚本本身锁定。你可以通过查看Arista Pyeapi文档(http://pyeapi.readthedocs.io/en/master/configfile.html#configfile ),找到那些包含在文件中的字段。这是我在实验中使用的文件:
image.png

第一行[connection:Arista1]包含我们将在Pyeapi连接中使用的名称;其余的字段应该是不言自明的。你可以为使用此文件用户将文件锁定为只读:
image.png

3.4.2.2 Pyeapi示例

现在,我们准备好了解一下使用情况。让我们首先通过在交互式Python shell中创建一个对象来连接到EOS节点:
image.png

我们可以对节点执行show命令并接收输出:
image.png
image.png

配置字段可以是单个命令,也可以是使用config()方法的命令列表:
image.png

请注意,命令缩写(show run与show running-config)和一些扩展将不起作用:
image.png

但是,你始终可以捕获结果并获得所需的值:
image.png

到目前为止,我们一直在使用eAPI执行显示和配置命令。Pyeapi提供各种API,让生活更轻松。在以下示例中,我们将连接到节点,调用VLAN API,并开始操作设备的VLAN参数。让我们来看看:
image.png
image.png

让我们验证是否在设备上创建了VLAN 10:
image.png

正如你所看到的,EOS对象上的Python原生API实际上是Pyeapi优于eAPI的地方。它将较低级别的属性抽象到设备对象中,使代码更清晰,更易于阅读。
警告:有关不断增加的Pyeapi API的完整列表,请查看官方文档(http://pyeapi.readthedocs.io/en/master/api_modules/_list_of_modules.html )。
为了完善本章,假设我们重复前面的步骤足够多次,以便编写另一个Python类来为我们节省一些工作。
pyeapi_1.py脚本如下所示:
image.png

从脚本中可以看出,我们会自动连接到节点并在连接时设置hostname和running_config。我们还为使用VLAN API创建VLAN的类创建了一种方法。让我们在交互式shell中试用脚本:
image.png

3.5 厂商中立的库

像Netmiko(https://github.com/ktbyers/netmiko)、NAPALM(https://github.com/napalm-automation/napalm )这样的与供应商无关的库已经做出了一些杰出的努力。由于这些库并非来自设备供应商,因此有时它们在支持最新平台或特性方面会慢一些。但是,由于库是与供应商无关的,如果你不喜欢将工具锁定在供应商,那么这些库是一个不错的选择。使用这些库的另一个好处是它们通常是开源的,所以你可以向上贡献新特性和缺陷修复。
另一方面,由于这些库是社区支持的,如果你需要依赖其他人来修复缺陷或实现新特性,那么它们不一定是理想的选择。如果你有一个相对较小的团队,仍然需要为你的工具遵守某些服务水平保证,那么你最好使用供应商支持的库。

3.6 小结

在本章中,我们研究了来自Cisco、Juniper和Arista的各种通信和管理网络设备的方法。我们研究了与NETCONF和REST等的直接通信,以及使用供应商提供的库(如PyEZ和Pyeapi)。这些是不同的抽象层,旨在提供一种无须人工干预就可以以编程方式管理网络设备的方法。
在第4章中,我们将研究一个更高层次的与供应商无关的抽象框架Ansible。Ansible是一个用Python编写的开源、通用的自动化工具。它可以用于自动化服务器、网络设备、负载平衡器等。当然,出于我们的目的,我们将重点介绍如何将这个自动化框架用于网络设备。

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

分享:

华章出版社

官方博客
官网链接