epiecs / mikodo
基于 phpmiko 的并发 Unix 兼容库,具有库存管理功能
Requires
- php: >=7.1
- ext-pcntl: *
- ext-sockets: *
- epiecs/phpmiko: ^1.0
- guzzlehttp/guzzle: ^6.3
- league/climate: ^3.5
- symfony/yaml: ^4.3
Requires (Dev)
- kint-php/kint: ^3.2
README
基于 phpmiko 的并发库。加快发送命令的过程。包含库存管理库。支持的库包括但不限于:Nornir yaml 文件、PhpIpam、...
需求
-
Php >= 7.1
-
ext-sockets
-
ext-pcntl
-
A UNIX 或 BSD OS。目前不支持原生 Windows,但可以使用 WSL。
安装
composer require epiecs/mikodo
支持的库存
已实现
- 基本
- Nornir
- PhpIpam
计划中
- Netbox
- ...
基本示例
初始化 Mikodo
require_once __DIR__ . '/vendor/autoload.php'; $mikodo = new \Epiecs\Mikodo\Mikodo();
缓冲区大小
每个工作进程与父进程通信可用的字节数。如果您需要发送大量文本(例如)完整的配置文件,请将此设置为更高的数字。您可以将此设置为较低的数字以减少内存使用,但您可能无法接收到所有输出。
$mikodo->bufferSize(65535); // Defaults to 65535
运行命令
Mikodo 使用与 Phpmiko 相同的 3 种方法向设备发送命令:cli、operation 和 configure。
在发送命令时,您可以通过字符串或命令的数组提供方法。两种方式都一样。当提供数组时,命令按顺序运行。
有关命令类型之间的区别,您可以参考 Phpmiko 文档
准备库存
Mikodo 使用库存来完成其魔法。最基本的方式是为 inventory() 方法提供一个由主机组成的数组
$mikodo->inventory([ 'Hostname_1' => [ 'device_type' => "junos", 'username' => "username", 'password' => "password", 'hostname' => "hostname or ip" ], 'Hostname_2' => [ 'device_type' => "junos", 'username' => "username", 'password' => "password", 'hostname' => "hostname or ip" ] ]);
每个主机至少应包括 Phpmiko 最基本所需信息:device_type、username、password 和 hostname。
发送命令(s)
当库存已准备就绪时,您就可以开始发送命令了。
$results = $mikodo->cli([ 'date', 'ping -c 2 8.8.8.8' ]);
如果一切顺利,您将看到如下输出。当然,在现实生活中,您将看到(漂亮的)颜色。
Starting mikodo, 2 queued jobs
[cli]
date
ping -c 2 8.8.8.8
=========================================================================> 100%
Retrieving output from Hostname_2
检索结果
Mikodo 将返回一个数组形式的值,您可以在其中为每个主机期望一个键,在该主机的键中,每个已运行的命令都还有一个键。
[ 'Hostname_1' => [ 'date' => " Wed Jul 24 15:48:36 CEST 2019 " 'ping -c 2 8.8.8' => " PING 8.8.8.8 (8.8.8.8): 56 data bytes 64 bytes from 8.8.8.8: icmp_seq=0 ttl=64 time=10.706 ms 64 bytes from 8.8.8.8: icmp_seq=1 ttl=64 time=11.214 ms --- 8.8.8.8 ping statistics --- 2 packets transmitted, 2 packets received, 0% packet loss round-trip min/avg/max/stddev = 10.706/10.960/11.214/0.254 ms " ] 'Hostname_2' => [ 'date' => " Wed Jul 24 15:48:36 CEST 2019 " 'ping -c 2 8.8.8.8' => " PING 8.8.8.8 (8.8.8.8): 56 data bytes 64 bytes from 8.8.8.8: icmp_seq=0 ttl=64 time=54.188 ms 64 bytes from 8.8.8.8: icmp_seq=1 ttl=64 time=11.252 ms --- 8.8.8.8 ping statistics --- 2 packets transmitted, 2 packets received, 0% packet loss round-trip min/avg/max/stddev = 11.252/32.720/54.188/21.468 ms " ] ]
打印结果
要将结果输出到终端,只需将返回的结果提供给 Mikodo->print() 函数。
$mikodo->print($results);
此外,在现实生活中,您应该得到漂亮的颜色。
Hostname_1
date
Wed Jul 24 15:33:48 CEST 2019
ping -c 2 8.8.8.8
PING 8.8.8.8 (8.8.8.8): 56 data bytes
64 bytes from 8.8.8.8 icmp_seq=0 ttl=64 time=10.798 ms
64 bytes from 8.8.8.8 icmp_seq=1 ttl=64 time=11.348 ms
--- 8.8.8.8 ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max/stddev = 10.798/11.073/11.348/0.275 ms
Hostname_2
date
Wed Jul 24 15:33:48 CEST 2019
ping -c 2 8.8.8.8
PING 8.8.8.8 (8.8.8.8): 56 data bytes
64 bytes from 8.8.8.8 icmp_seq=0 ttl=64 time=11.876 ms
64 bytes from 8.8.8.8 icmp_seq=1 ttl=64 time=11.193 ms
--- 8.8.8.8 ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max/stddev = 11.193/11.534/11.876/0.341 ms
库存
为了使您的生活更轻松,Mikodo 包含了几个库存提供者。
库存允许您轻松选择库存中的特定主机和/或组。库存还允许您在全局和/或组级别设置默认值。
您甚至可以混合和匹配不同的库存。一个例子可以是加载 PhpIpam 中的所有主机,并通过简单库存提供默认的用户名/密码。
您必须注意的一个注意事项是设置的顺序。
优先顺序是主机 > 组 > 默认值。想象一下这种情况:您有一个库存,并在默认设置中设置了默认的用户名和密码。在您的库存中,还有一个主机,其中在主机配置中设置了密码。
主机中定义的密码将优先于默认设置中提供的密码。
编写自己的库存提供者
所有库存提供者都可以扩展基本库存类,并应实现DeviceInterface接口。
建议扩展基本Inventory类并使用sethosts/setgroups/setdefaults命令。这些命令将确保配置按预期正确合并。
InventoryInterface提供了一种很好的结构,说明包含主机、组和默认值的数组应该如何工作。
基本库存
基本库存可以通过三种方式初始化
- 通过构造函数
- 通过设置器
- 两者的组合
示例
require_once __DIR__ . '/vendor/autoload.php'; use Epiecs\Mikodo\Mikodo; use Epiecs\Mikodo\InventoryProviders\BaseInventory; $baseInventory = new BaseInventory(); // Sethosts is used here but you can always use the constructor if you'd like $baseInventory->setGroups([ 'core_switches' => [ 'device_type' => "cisco_ios", ], 'lab_switches' => [ 'username' => 'lab_username', 'password' => 'lab_password', 'port' => 2020 ] ]); $baseInventory->setDefaults([ 'port' => 22, 'username' => "defaultusername", 'password' => "defaultpassword" ]); $baseInventory->setHosts([ 'Hostname_1' => [ 'device_type' => 'junos', 'port' => 22, 'username' => 'my_default_username', 'password' => 'my_default_password', 'hostname' => '192.168.0.1', 'groups' => [ 'core_switches', ], ], 'Hostname_2' => [ 'device_type' => 'junos', 'port' => 22, 'username' => 'my_default_username', 'password' => 'my_default_password', 'hostname' => '192.168.0.1', 'groups' => [ 'core_switches' ] ], 'Hostname_3' => [ 'device_type' => 'cisco_ios', 'port' => 22, 'hostname' => '172.16.2.10', 'groups' => [ 'lab_switches', 'core_switches' ] ], ]); $mikodo = new Mikodo(); $mikodo->inventory($baseInventory->getGroups(['lab_swithches', 'core_switches']));
以下方法被支持
$baseInventory = new BaseInventory(array $hosts = array(), array $groups = array(), array $defaults = array()); // Setting the inventory $baseInventory->setHosts(array $hosts); $baseInventory->setGroups(array $groups); $baseInventory->setDefaults(array $defaults); // Get all hosts $baseInventory->getHosts(array $hosts); // Get all groups provided in the $groups array $baseInventory->getGroups(array $groups); // Get all groups provided in the $groups array and reduce with the groups within the $filterGroups array $baseInventory->getGroups(array $groups, array $filterGroups); // Get the full inventory. Usefull if you need to modify it yourself. $baseInventory->getInventory();
getGroups方法
当使用getGroups方法时,有一个可选参数叫做$groups。
根据在$groups参数中提供的组名,从库存中获取所有主机。
当提供了一个包含filterGroups的数组时,库存将返回只包含$groups和$filterGroups数组中的组的二分搜索结果
$groups数组将结果集填充为所有提供的组,而$filterGroups有助于减少它
例如,如果您请求cisco和switches组中的所有设备,并且只想使用也是nexus和europe组成员的设备
$groups = ['cisco', 'switches']; $filterGroups = ['nexus', 'eu']; $baseInventory->getGroups(array $groups, array $filterGroups);
PhpIpam库存
Mikodo可以使用现有的PhpIpam实例。库存提供者将从phpipam获取所有设备,并将某些组自动应用于每个主机名,只要phpipam中对应的值存在且不为空。
之后,如果需要,您仍然可以通过提供的库存方法设置组和/或默认设置。
将为
- 每种在phpipam中已知的设备类型应用一个组。
- 该设备的机架(们)
- 该设备所属的区(们)
- 该设备的位置(们)
- 如果为设备设置了自定义字段。
如果为用户名、密码、端口和/或设备类型提供了自定义字段,则不会将其作为组应用,而是直接应用于主机对象。这样就可以在PhpIpam中设置一些默认值
如果您愿意,也可以提供一个名为'groups'的自定义字段,其中包含逗号分隔的组。这些组将被添加到该设备的已知组中。
以下认证方法被支持
- 用户令牌(未加密,需要用户名和密码)
- 带有用户令牌的SSL(加密,需要用户名和密码),提供https api链接
- 带有应用代码令牌的SSL(加密,需要应用代码),提供https链接
$ipamUrl = 'https://phpipam.local/api' $appId = 'ipamappId' $username = 'ipamuser'; $password = 'ipampassword'; $appCode = 'ipamAppCode'; // When using username and password $phpipamInventory = new \Epiecs\Mikodo\InventoryProviders\PhpipamInventory($ipamUrl, $appId, $username, $password); // When using an app code token $phpipamInventory = new \Epiecs\Mikodo\InventoryProviders\PhpipamInventory($ipamUrl, $appId, "", "", $appCode); // Set the group and default settings if neccesary $phpipamInventory->setGroups([ 'switch' => [ 'device_type' => "cisco_ios", 'password' => "password" ], 'firewall' => [ 'device_type' => "junos", 'port' => 2020 ] ]); $phpipamInventory->setDefaults([ 'port' => 22, 'username' => "defaultusername", 'password' => "defaultpassword" ]); $mikodo = new \Epiecs\Mikodo\Mikodo(); $mikodo->inventory($phpipamInventory->getGroups(['Switch']));
Nornir库存
如果您喜欢Nornir,您很可能已经有了Nornir库存。在我的项目文件夹中,我有以下目录结构
└── inventory
├── defaults.yaml
├── groups.yaml
└── hosts.yaml
您可以使用NornirInventory提供者加载此目录,并像使用基本库存一样查询它。所需文件仅为hosts.yaml文件。
为了简化起见,我将使用以下库存作为参考。虽然简短,但足以作为一个示例,向您展示所有库存组件的优先级。
default.yaml
--- port: 22 username: my_default_username password: my_default_password
groups.yaml
--- core_switches: device_type: junos lab_switches: device_type: cisco_ios port: 2000
hosts.yaml
--- Hostname_1: hostname: 192.168.0.1 groups: - core_switches Hostname_2: hostname: 192.168.0.1 groups: - core_switches Hostname_3: hostname: 172.16.2.10 groups: - lab_switches Hostname_4: hostname: 172.16.2.20 groups: - lab_switches Hostname_5: hostname: 172.16.2.30 groups: - lab_switches Hostname_6: hostname: 172.16.2.50 groups: - lab_switches - core_switches
$nornirInventory = new \Epiecs\Mikodo\InventoryProviders\NornirInventory(__DIR__ . DIRECTORY_SEPARATOR . 'inventory'); $mikodo = new \Epiecs\Mikodo\Mikodo(); $mikodo->inventory($nornirInventory->getGroups(['lab_switches', 'core_switches']));