尝试将NSO与Ansible结合起来
首先
本文是由思科的同志作为“冒险日历”的一部分投稿的。
「网络自动化」这一概念已经被提出一段时间了,为此出现了许多解决方案。在进行「网络自动化」时,需要确定具体目标,并相应地组合所需解决方案,以实现更顺畅的自动化过程。
思科提供的解决方案之一是Network Services Orchestrator (NSO)。它是用作自动化设备配置和作为选择所需设备的编排器的框架。它经常被用作工作流管理工具或用于配置网络设备的工具。
希望您也可以参考之前的这篇文章,了解概述部分。思科网络服务编排器(NSO)能够实现的功能。
Ansible 是一個由 Redhat 公司擁有的開源自動化解決方案。在冪等性政策的基礎上,它使用了許多已登錄的模塊,可以進行遠程設備的配置。
本文介绍了如何将这两种方法结合起来使用。
NSO 和 Ansible 的不同之处
有人可能会想到为什么会有人将NSO和Ansible进行比较,因为它们本质上是不同的产品。然而,事实上,很多时候人们把NSO的“Orchestrator”部分剔除出来进行比较。虽然它们有不同的目的,但从配置远程设备的角度来比较一下。
NSO可以做到的事情,Ansible办不到。
在进行网络设备配置方面,两者都可以做类似的事情。例如,如果你想要将 Cisco IOS 路由器上的接口 Ethernet 1/1 的描述从 “hello” 改为 “cisco”,在 NSO 中你可以使用 Cisco IOS NED,在 Ansible 中你可以使用 ios_config 模块。
如果想要将设置的值恢复到原来的状态,该怎么办呢?在NSO中有一个回滚功能,可以自动生成像”描述 你好”这样的命令,但在Ansible中需要以某种方式保存原始值,并准备一个用于再次更改的Playbook。这是因为NSO会保存设备的状态信息,并且具有命令的模式信息,所以才可以实现这个功能。
只需要一个选项,用中文将以下内容重新表达:
用 Ansible 能做到的事情,NSO 做不到。
Ansible的服务器设置功能非常出色,并且NSO的NED没有特别针对它,因此在使用NSO的环境中使用Ansible也具有重要意义。例如,在Redhat Linux上安装Apache软件包,可以通过使用非常简单的Playbook来实现。
使用Ansible来操作NSO
其实,Ansible也有一个名为 nso 的模块。
-
- nso_config
-
- nso_action
-
- nso_query
-
- nso_show
- nso_verify
通过使用这些,可以从Ansible控制NSO。在内部,使用了REST,并且还可以扩展NSO提供的北向接口。
在这篇文章中,我想尝试使用Ansible来对NSO进行反向操作。
使用 Ansible 通过 NSO 来进行操作
NSO是一个Orchestrator,但通常与之配套使用的NED非常重要,这也是NSO的一个重要吸引点之一。它承担管理远程设备的角色,并成为与Southbound连接的接入点。
如果使用CLI NED,则使用内置的telnet/ssh客户端。如果使用NETCONF NED,则将NSO内部的NETCONF模块用于外部使用。(因此,CLI NED的SSH客户端和NETCONF NED的SSH客户端是不同的)
在中文中的某个选项:还有一个通用NED,这个NED不是用于telnet/ssh/netconf的Southbound连接。对于telnet/ssh/netconf NED,NSO会进行一定程度的管理,但对于通用NED,需要在NED内部管理所有内容,但可以支持各种Southbound连接。例如,为了连接到Cisco ACI的APIC,需要理解APIC的REST协议,但实现为通用NED。
通用NED的实现
数据模型
服务器的设置包括需要进行”设置”的内容以及不可改变的内容。同时,在服务器运行时还可能有数据被修改的情况。
– 配置 – config
– 不变数据 – 运行数据
– 动态数据 – 实时状态(运行数据)
需要对这些进行建模。
这次我已经制作了以下内容。
模块 linux {
命名空间 “http://com/example/linux”;
前缀 linux;
导入 tailf-ncs {
前缀 ncs;
}
导入 tailf-common {
前缀 tailf;
}
导入 linux-gen {
前缀 family;
}
容器 dns {
叶列表 name-servers {
类型 string;
}
叶列表 search {
类型 string;
}
}
叶 hostname {
类型 string;
}
列表 packages {
键名 name;
叶 name {
类型 string;
}
叶 service-state {
类型 枚举 {
枚举值 started;
枚举值 stopped;
}
}
httpd-param {
当 “../name = ‘httpd'”;
列表 vserver {
键名 name;
叶 name {
类型 string;
}
}
}
容器 samba-param {
当 “../name = ‘samba'”;
}
tailf:动作 restart {
tailf:动作点 restart;
}
}
容器 firewall {
叶列表 open-port {
类型 string;
}
}
}
module linux-oper {
namespace “http://com/example/linux”;
prefix linux;
tailf-ncsをインポート {
prefix ncs;
}
tailf-commonをインポート {
prefix tailf;
}
linux-genをインポート {
prefix family;
}
ncs:devices/ncs:deviceを拡張 {
when “derived-from(./ncs:device-type/ncs:generic/ncs:ned-id,’family:linux-gen’)”;
linux-factsというコンテナー {
config false;
tailf:cdb-oper {
tailf:persistent true;
}
architectureというリーフ {
type string;
}
bios_dateというリーフ {
type string;
}
bios_versionというリーフ {
type string;
}
distributionというリーフ {
type string;
}
distribution_releaseというリーフ {
type string;
}
distribution_versionというリーフ {
type string;
}
tzというリーフ {
type string;
}
devicesというリスト {
nameをキーに持つ;
nameというリーフ {
type string;
}
}
}
}
}
在进行“list packages”时,我们会将包信息列成列表并进行设置。此外,各种不变数据都存储在操作数据中。
获取数据
获取服务器状态可以使用Ansible Facts。具体而言,可以通过使用 setup、packages_facts 和 services_facts 模块来获取所需的信息。
以下是主要需要进行的工作:
– 在NED的show方法中执行ansible命令,以json格式获取数据
– 将获取的数据映射到已创建的设备模型中。
即使在创建NED时,对于对CDB的路径操作,基本上与创建服务时一样。
用于数据获取的ansible命令。
通常使用Ansible时需要ansible.cfg和inventory文件。但是,如果使用NED,目标可能会变化,需要在执行命令前创建文件。它就像缓存文件一样,如果可能的话,不想创建它。
因此,决定通过Adhoc命令获取,并编写以下代码。
模块中包含setup,package_facts和service_facts。
ProcessBuilder pb = new ProcessBuilder(
"ansible",
"-i",
host+",",
"all",
"-e",
"ansible_user="+user+ " ansible_password="+password,
"-b",
"-m",
module
);
Map<String, String> env = pb.environment();
env.put("ANSIBLE_REMOTE_TMP", "/tmp");
env.put("ANSIBLE_STDOUT_CALLBACK", "json");
env.put("ANSIBLE_LOAD_CALLBACK_PLUGINS", "True");
Process p = pb.start();
如果想在Linux上实际运行,请尝试以下方法:
通过ANSIBLE_STDOUT_CALLBACK环境变量,可以将输出设置为JSON格式。要在Adhoc命令中更改它,请设置ANSIBLE_LOAD_CALLBACK_PLUGINS环境变量。
ANSIBLE_REMOTE_TMP=/tmp ANSIBLE_STDOUT_CALLBACK=json ANSIBLE_LOAD_CALLBACK_PLUGINS=True ansible -i 192.168.1.1, all -e "ansible_user=ansible ansible_password=ansible123" -m setup -b
我使用了nanojson库来解析Json。由于可以直接使用从p.getInputStream()创建的输出,所以非常方便处理。
JsonObject ob = JsonParser.object().from(jsonOutputSb.toString());
obForHost = ob.getArray("plays")
.getObject(0)
.getArray("tasks")
.getObject(0)
.getObject("hosts").getObject(host).getObject("ansible_facts");
生成 Ansible playbook 以进行数据更改
如果在NSO中创建了一个包含“添加包”等差异(diff)的操作,将会根据这个操作创建相应的playbook。
使用ncs-make-packages命令创建模板时,将会生成与MOP相匹配的方法的代码。本次使用了生成的代码,所以NedEditOp.CREATED的结果如下所示。
AnsiblePlaybook/Task 类是为了创建本次所需的 yaml 文件而创建的实用类。
public void create(NedWorker worker, NedEditOp op, AnsiblePlaybook ap, StringBuilder dryRun)
throws Exception {
ConfObject[] kp = getKP(op);
ConfKey key = (ConfKey)kp[0];
ConfTag tag = (ConfTag)kp[1];
if(tag.getTag().equals("packages")){
// new package is added
Task yumTask = new Task("yum");
ap.addTask(yumTask);
yumTask.addParam("name", key.elementAt(0).toString());
yumTask.addParam("state", "latest");
}
同样,我们也会对NedEditOp.DELETED/NedEditOp.VALUE_SET进行实现。
完成品 – translated as “finished product” in English.
我将尝试使用创建的通用NED。使用该NED进行NSO配置与使用其他NED时没有区别。
admin@ncs# show running-config devices device webserver
devices device webserver
address 192.168.1.1
port 22
authgroup webserver
device-type generic ned-id linux-gen-1.0
state admin-state unlocked
admin@ncs#
尝试进行同步
通过Ansible Adhoc命令获得的内容已经存入了CDB中。
admin@ncs# devices device webserver sync-from
result true
admin@ncs#
admin@ncs# show running-config devices device webserver config services
devices device webserver
config
services NetworkManager-dispatcher.service
status enabled
!
services NetworkManager-wait-online.service
status enabled
!
services NetworkManager.service
status enabled
!
...
admin@ncs# show running-config devices device webserver config packages
devices device webserver
config
packages NetworkManager
!
packages NetworkManager-libnm
!
packages NetworkManager-team
!
packages NetworkManager-tui
...
我们将一个不变的值作为操作数据。
admin@ncs# show devices device webserver linux-facts
linux-facts architecture x86_64
linux-facts bios_date 12/12/2018
linux-facts bios_version 6.00
linux-facts distribution CentOS
linux-facts distribution_release Core
linux-facts distribution_version 7.7
admin@ncs#
尝试安装或删除包。
根据NSO所创建的差异(diff),我们会制作一份适合ansible使用的合适playbook。
admin@ncs# conf
Entering configuration mode terminal
admin@ncs(config)# devices device webserver config
admin@ncs(config-config)# packages httpd
admin@ncs(config-packages-httpd)# packages firewalld
admin@ncs(config-packages-firewalld)# firewall open-port [ 80 443 ]
admin@ncs(config-config)# services httpd
admin@ncs(config-services-httpd)# status enabled
admin@ncs(config-services-httpd)# exit
admin@ncs(config-config)# no packages acl
admin@ncs(config-config)# commit dry-run outformat native
native {
device {
name webserver
data - name: Configuration from NSO
hosts: 192.168.1.1
tasks:
- service:
name: httpd
state: started
enabled: enabled
- yum:
name: acl
state: absent
- yum:
name: httpd
state: latest
- firewalld:
port: 443
permanent: yes
state: enabled
- firewalld:
port: 80
permanent: yes
state: enabled
}
}
admin@ncs(config-config)#
由于已经安装了firewalld,所以没有创建diff。因此,上述结果中不包括它。关于NSO的好处是,忽略了Ansible幂等性的优点(笑
在后端,以下等效的功能将被执行。不幸的是,为了执行ansible-playbook命令,必须创建一个yaml文件,因此放弃了完整的”一行命令”。
$ ANSIBLE_REMOTE_TMP=/tmp ANSIBLE_STDOUT_CALLBACK=json ANSIBLE_LOAD_CALLBACK_PLUGINS=True ansible-playbook -i 192.168.1.1, -e "ansible_user=root ansible_password=cisco123" test.yaml
回滚! (Huí !)
NSO的优点是能够创建rollback的差异,并能够自动生成相应的playbook。这对于独立使用Ansible来说可能很困难。
admin@ncs(config)# rollback configuration
admin@ncs(config)# commit dry-run
cli {
local-node {
data devices {
device webserver {
config {
+ packages acl {
+ }
- packages httpd {
- }
- services httpd {
- status enabled;
- }
firewall {
- open-port [ 443 80 ];
}
}
}
}
}
}
admin@ncs(config)#
admin@ncs(config)# commit dry-run outformat native
native {
device {
name webserver
data - name: Configuration from NSO
hosts: 192.168.1.1
tasks:
- service:
name: httpd
enabled: disabled
- yum:
name: acl
state: latest
- yum:
name: httpd
state: absent
- firewalld:
port: 443
permanent: yes
state: disabled
- firewalld:
port: 80
permanent: yes
state: disabled
}
}
admin@ncs(config)#
由于首次更改,已删除了acl包,因此需要重新安装。
最后
这个例子似乎将 NSO 和 Ansible 结合起来使用,得到了一个很好的结果。由于目前 Cisco 还没有发布 Ansible Generic NED,所以用户自己尝试创建也是一个有趣的想法。
从现在开始,我们不再是NSO与Ansible的对立,而是要通过NSO与Ansible相结合,一同前进吧!
免责条款
在本网站和相关评论中表达的观点是发表者个人观点,不代表思科的观点。本网站的内容仅供信息提供,不旨在获得思科或其他相关人士的认可或陈述。每个用户通过在本网站上发布、链接或以其他方式上传的所有信息内容,承担全部责任,并同意解除思科与使用本网站所产生的任何责任。