net-connector 0.4.0 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +73 -65
- data/README.md +88 -95
- data/docs/VERIFICATION.md +2 -1
- data/docs/architecture.md +144 -248
- data/lib/net/connector/device/base.rb +1 -0
- data/lib/net/connector/device/interface_description.rb +3 -0
- data/lib/net/connector/device/profile/builder.rb +236 -0
- data/lib/net/connector/device/profile.rb +2 -227
- data/lib/net/connector/device/running_config/strategy.rb +5 -0
- data/lib/net/connector/device/running_config.rb +5 -0
- data/lib/net/connector/engine/dialogue.rb +1 -0
- data/lib/net/connector/engine/errors.rb +2 -0
- data/lib/net/connector/engine/log.rb +13 -9
- data/lib/net/connector/engine/session.rb +1 -0
- data/lib/net/connector/netdisco/cli.rb +20 -20
- data/lib/net/connector/netdisco/device.rb +4 -8
- data/lib/net/connector/netdisco/fleet.rb +2 -48
- data/lib/net/connector/netdisco/plan.rb +77 -0
- data/lib/net/connector/netdisco/planner.rb +12 -23
- data/lib/net/connector/netdisco/worker.rb +31 -24
- data/lib/net/connector/operations/tftp/file_upload.rb +42 -0
- data/lib/net/connector/operations/tftp/strategy.rb +9 -11
- data/lib/net/connector/operations/topology/strategy.rb +14 -0
- data/lib/net/connector/operations/topology.rb +1 -0
- data/lib/net/connector/vendor/cisco_ios/running_config.rb +1 -0
- data/lib/net/connector/vendor/cisco_ios/topology.rb +9 -0
- data/lib/net/connector/vendor/cisco_nxos/running_config.rb +1 -0
- data/lib/net/connector/vendor/h3c/tftp_backup.rb +2 -18
- data/lib/net/connector/vendor/h3c/topology.rb +9 -0
- data/lib/net/connector/vendor/hillstone/running_config.rb +1 -0
- data/lib/net/connector/vendor/hillstone/tftp_backup.rb +4 -0
- data/lib/net/connector/vendor/hillstone/topology.rb +9 -0
- data/lib/net/connector/vendor/huawei/tftp_backup.rb +2 -18
- data/lib/net/connector/vendor/palo_alto/running_config.rb +4 -0
- data/lib/net/connector/vendor/palo_alto/tftp_backup.rb +7 -5
- data/lib/net/connector/vendor/palo_alto/topology.rb +10 -0
- data/lib/net/connector/vendor/radware/tftp_backup.rb +2 -2
- data/lib/net/connector/vendor/radware/topology.rb +2 -0
- data/lib/net/connector/version.rb +1 -1
- metadata +26 -24
|
@@ -6,6 +6,9 @@ module Net
|
|
|
6
6
|
module Connector
|
|
7
7
|
module Hillstone
|
|
8
8
|
class TftpBackup < Operations::Tftp::Strategy
|
|
9
|
+
# 山石原生导出的配置文件使用 dat 扩展名。
|
|
10
|
+
def self.file_extension = "dat"
|
|
11
|
+
|
|
9
12
|
# 构造当前厂商的 TFTP 导出交互脚本。
|
|
10
13
|
def script(target, source_file:, vrf: nil)
|
|
11
14
|
raise ArgumentError, "Hillstone TFTP export does not use source_file" if source_file
|
|
@@ -31,6 +34,7 @@ module Net
|
|
|
31
34
|
|
|
32
35
|
private
|
|
33
36
|
|
|
37
|
+
# 仅认可设备明确给出目标文件名的 Export ok 回显。
|
|
34
38
|
def completion_line(result)
|
|
35
39
|
completion_lines(result).find { |line| line.match?(/\AExport\s+ok\s*,\s*target\s+file\s+name\s+\S+\z/i) }
|
|
36
40
|
end
|
|
@@ -6,15 +6,21 @@ module Net
|
|
|
6
6
|
module Connector
|
|
7
7
|
module Hillstone
|
|
8
8
|
class Topology < Operations::Topology::Strategy
|
|
9
|
+
# 山石提供 LLDP 邻居、配置描述读取和描述变更。
|
|
9
10
|
def self.supports?(capability)
|
|
10
11
|
%i[neighbors interface_descriptions interface_description_changes].include?(capability)
|
|
11
12
|
end
|
|
12
13
|
|
|
14
|
+
# 读取 LLDP 邻居信息。
|
|
13
15
|
def neighbor_command = "show lldp neighbor-information"
|
|
16
|
+
# 从运行配置解析接口描述。
|
|
14
17
|
def description_template = "hillstone_interface_descriptions.textfsm"
|
|
18
|
+
# 进入配置视图。
|
|
15
19
|
def enter_configuration = "configure"
|
|
20
|
+
# 退出配置视图并保存设备配置。
|
|
16
21
|
def finish_commands = ["exit"] + @device.profile.save_commands
|
|
17
22
|
|
|
23
|
+
# 用数据行和设备报告的总数交叉核对,避免遗漏邻居。
|
|
18
24
|
def expected_neighbor_count(output, _template)
|
|
19
25
|
reported = output[/Total lldp neighbor number:\s*(\d+)/i, 1]
|
|
20
26
|
lines = neighbor_lines(output)
|
|
@@ -24,17 +30,20 @@ module Net
|
|
|
24
30
|
lines.size
|
|
25
31
|
end
|
|
26
32
|
|
|
33
|
+
# 仅在列表为空且有明确零邻居证据时认可空表。
|
|
27
34
|
def empty_neighbor_output?(output)
|
|
28
35
|
neighbor_lines(output).empty? && (output.match?(/Total lldp neighbor number:\s*0\b/i) ||
|
|
29
36
|
output.match?(/System Name\s+Local Interface/i))
|
|
30
37
|
end
|
|
31
38
|
|
|
39
|
+
# 复用公共接口描述命令。
|
|
32
40
|
def change_commands(change)
|
|
33
41
|
InterfaceDescription.commands(interface: change.interface, description: change.new_description)
|
|
34
42
|
end
|
|
35
43
|
|
|
36
44
|
private
|
|
37
45
|
|
|
46
|
+
# 去掉命令、表头、总数和提示符,只保留邻居数据行。
|
|
38
47
|
def neighbor_lines(output)
|
|
39
48
|
output.lines.map(&:strip).reject do |line|
|
|
40
49
|
line.empty? || line == neighbor_command || line.match?(/\ASystem Name\s+Local Interface\b/i) ||
|
|
@@ -1,33 +1,17 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require_relative "../../operations/tftp/
|
|
3
|
+
require_relative "../../operations/tftp/file_upload"
|
|
4
4
|
|
|
5
5
|
module Net
|
|
6
6
|
module Connector
|
|
7
7
|
module Huawei
|
|
8
|
-
class TftpBackup < Operations::Tftp::
|
|
8
|
+
class TftpBackup < Operations::Tftp::FileUpload
|
|
9
9
|
# 要求调用方提供合法的华为启动配置文件路径。
|
|
10
10
|
def source_file(value)
|
|
11
11
|
raise ArgumentError, "Huawei TFTP backup requires source_file" unless value
|
|
12
12
|
|
|
13
13
|
TftpTarget.validate_source_file!(value)
|
|
14
14
|
end
|
|
15
|
-
|
|
16
|
-
# 根据华为配置源文件确定默认导出名称。
|
|
17
|
-
def default_path(source_file) = File.basename(source_file)
|
|
18
|
-
|
|
19
|
-
# 构造当前厂商的 TFTP 导出交互脚本。
|
|
20
|
-
def script(target, source_file:, vrf: nil)
|
|
21
|
-
raise ArgumentError, "Huawei TFTP backup does not use vrf" if vrf
|
|
22
|
-
|
|
23
|
-
destination = target.explicit_path? ? " #{target.path}" : ""
|
|
24
|
-
Script.new([Command.new("tftp #{target.host} put #{source_file}#{destination}", timeout: 180)])
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
# 检查设备回显是否确认 TFTP 传输完成。
|
|
28
|
-
def complete?(result)
|
|
29
|
-
completion_lines(result).any? { |line| completed_upload?(line) }
|
|
30
|
-
end
|
|
31
15
|
end
|
|
32
16
|
end
|
|
33
17
|
end
|
|
@@ -7,6 +7,7 @@ module Net
|
|
|
7
7
|
module Connector
|
|
8
8
|
module PaloAlto
|
|
9
9
|
class RunningConfig < Net::Connector::RunningConfig::Strategy
|
|
10
|
+
# 配置位于 show 步骤,最后的 exit 只负责离开候选视图。
|
|
10
11
|
def result_step(result)
|
|
11
12
|
result.steps.find { |step| step.command.text == "show" }
|
|
12
13
|
end
|
|
@@ -21,6 +22,7 @@ module Net
|
|
|
21
22
|
end
|
|
22
23
|
end
|
|
23
24
|
|
|
25
|
+
# 采集前后都检查候选差异,拒绝把未提交配置误作运行配置。
|
|
24
26
|
def check_response(command, response, _execution)
|
|
25
27
|
return unless command.text == "show config diff"
|
|
26
28
|
return if body(response.output, command.text).empty?
|
|
@@ -29,6 +31,7 @@ module Net
|
|
|
29
31
|
code: :uncommitted_configuration, host: @device.host, phase: :collect)
|
|
30
32
|
end
|
|
31
33
|
|
|
34
|
+
# 只接受完整的 set 命令文本,排除 XML 或截断的引号配置。
|
|
32
35
|
def clean(text)
|
|
33
36
|
normalized = body(text, "show").sub(/(?:\A|\n)[ \t]*\[edit\][ \t]*\z/, "").strip
|
|
34
37
|
unless set_commands?(normalized)
|
|
@@ -60,6 +63,7 @@ module Net
|
|
|
60
63
|
pending.empty?
|
|
61
64
|
end
|
|
62
65
|
|
|
66
|
+
# 去掉命令回显和提示符,保留真正需要校验的设备响应。
|
|
63
67
|
def body(text, command)
|
|
64
68
|
text.gsub("\r\n", "\n").sub(/\A[ \t]*#{Regexp.escape(command)}[ \t]*\n/, "")
|
|
65
69
|
.sub(@device.profile.command_prompt, "").strip
|
|
@@ -6,18 +6,20 @@ module Net
|
|
|
6
6
|
module Connector
|
|
7
7
|
module PaloAlto
|
|
8
8
|
class TftpBackup < Operations::Tftp::Strategy
|
|
9
|
+
FILENAME = "running-config.xml"
|
|
10
|
+
|
|
9
11
|
# 返回 PAN-OS 固定使用的运行配置文件名。
|
|
10
|
-
def
|
|
12
|
+
def self.filename(_host, **) = FILENAME
|
|
11
13
|
|
|
12
14
|
# 构造当前厂商的 TFTP 导出交互脚本。
|
|
13
15
|
def script(target, source_file:, vrf: nil)
|
|
14
16
|
raise ArgumentError, "PAN-OS does not use source_file" if source_file
|
|
15
17
|
raise ArgumentError, "PAN-OS TFTP backup does not use vrf" if vrf
|
|
16
|
-
unless target.path ==
|
|
17
|
-
raise ArgumentError, "PAN-OS TFTP export uses the fixed filename
|
|
18
|
+
unless target.path == FILENAME
|
|
19
|
+
raise ArgumentError, "PAN-OS TFTP export uses the fixed filename #{FILENAME}"
|
|
18
20
|
end
|
|
19
21
|
|
|
20
|
-
Script.new([Command.new("tftp export configuration to #{target.host} from
|
|
22
|
+
Script.new([Command.new("tftp export configuration to #{target.host} from #{FILENAME}",
|
|
21
23
|
timeout: 180)])
|
|
22
24
|
end
|
|
23
25
|
|
|
@@ -29,7 +31,7 @@ module Net
|
|
|
29
31
|
end
|
|
30
32
|
|
|
31
33
|
# 返回 PAN-OS 实际上传的固定文件名。
|
|
32
|
-
def remote_path(_target, _result) =
|
|
34
|
+
def remote_path(_target, _result) = FILENAME
|
|
33
35
|
end
|
|
34
36
|
end
|
|
35
37
|
end
|
|
@@ -6,19 +6,26 @@ module Net
|
|
|
6
6
|
module Connector
|
|
7
7
|
module PaloAlto
|
|
8
8
|
class Topology < Operations::Topology::Strategy
|
|
9
|
+
# PAN-OS 提供 LLDP 邻居、接口备注读取和备注变更。
|
|
9
10
|
def self.supports?(capability)
|
|
10
11
|
%i[neighbors interface_descriptions interface_description_changes].include?(capability)
|
|
11
12
|
end
|
|
12
13
|
|
|
14
|
+
# 读取各本机接口的 LLDP 邻居详情。
|
|
13
15
|
def neighbor_command = "show lldp neighbors all"
|
|
16
|
+
# 从 set 格式配置解析接口备注。
|
|
14
17
|
def description_template = "palo_alto_interface_descriptions.textfsm"
|
|
18
|
+
# 进入候选配置视图。
|
|
15
19
|
def enter_configuration = "configure"
|
|
20
|
+
# 提交候选配置后退出配置视图。
|
|
16
21
|
def finish_commands = ["commit", "exit"]
|
|
17
22
|
|
|
23
|
+
# 只计入非空邻居块,跳过没有对端的本机接口。
|
|
18
24
|
def expected_neighbor_count(output, _template)
|
|
19
25
|
neighbor_blocks(output).count { |block| !empty_neighbor_block?(block) }
|
|
20
26
|
end
|
|
21
27
|
|
|
28
|
+
# 输出必须明确说明无邻居,或每个本机接口块都明确为空。
|
|
22
29
|
def empty_neighbor_output?(output)
|
|
23
30
|
return true if output.match?(/No LLDP neighbors/i)
|
|
24
31
|
|
|
@@ -34,6 +41,7 @@ module Net
|
|
|
34
41
|
output.split(/^\s*Local information:\s*$/i).select { |block| block.match?(/^\s*Local interface:\s*\S+/i) }
|
|
35
42
|
end
|
|
36
43
|
|
|
44
|
+
# 邻居字段区只有空行和提示符时,才视为明确的空块。
|
|
37
45
|
def empty_neighbor_block?(block)
|
|
38
46
|
tail = block.split(/^\s*Neighbor information:\s*$/i, 2)
|
|
39
47
|
tail.size == 2 && tail.last.lines.all? { |line| line.strip.empty? || line.match?(/^\S+[>#]\s*$/) }
|
|
@@ -50,10 +58,12 @@ module Net
|
|
|
50
58
|
code: :unrecognized_output, host: @device.host, phase: :parse)
|
|
51
59
|
end
|
|
52
60
|
|
|
61
|
+
# 用 PAN-OS set 语法生成接口备注变更。
|
|
53
62
|
def change_commands(change)
|
|
54
63
|
[%Q(set network interface ethernet #{change.interface} comment "#{change.new_description}")]
|
|
55
64
|
end
|
|
56
65
|
|
|
66
|
+
# commit 可能耗时较长,单独放宽该命令的超时。
|
|
57
67
|
def script_command(command)
|
|
58
68
|
command == "commit" ? Command.new(command, timeout: 300) : command
|
|
59
69
|
end
|
|
@@ -6,8 +6,8 @@ module Net
|
|
|
6
6
|
module Connector
|
|
7
7
|
module Radware
|
|
8
8
|
class TftpBackup < Operations::Tftp::Strategy
|
|
9
|
-
#
|
|
10
|
-
def
|
|
9
|
+
# Radware 原生导出生成压缩配置归档。
|
|
10
|
+
def self.file_extension = "tgz"
|
|
11
11
|
|
|
12
12
|
# 构造当前厂商的 TFTP 导出交互脚本。
|
|
13
13
|
def script(target, source_file:, vrf: nil)
|
|
@@ -6,7 +6,9 @@ module Net
|
|
|
6
6
|
module Connector
|
|
7
7
|
module Radware
|
|
8
8
|
class Topology < Operations::Topology::Strategy
|
|
9
|
+
# Alteon 只支持读取端口描述,不提供邻居发现或自动改写。
|
|
9
10
|
def self.supports?(capability) = capability == :interface_descriptions
|
|
11
|
+
# 从设备配置转储解析端口名称。
|
|
10
12
|
def description_template = "radware_port_names.textfsm"
|
|
11
13
|
end
|
|
12
14
|
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: net-connector
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.4.
|
|
4
|
+
version: 0.4.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- net-connector contributors
|
|
@@ -23,26 +23,6 @@ dependencies:
|
|
|
23
23
|
- - "~>"
|
|
24
24
|
- !ruby/object:Gem::Version
|
|
25
25
|
version: 0.3.1
|
|
26
|
-
- !ruby/object:Gem::Dependency
|
|
27
|
-
name: activesupport
|
|
28
|
-
requirement: !ruby/object:Gem::Requirement
|
|
29
|
-
requirements:
|
|
30
|
-
- - ">="
|
|
31
|
-
- !ruby/object:Gem::Version
|
|
32
|
-
version: '7.2'
|
|
33
|
-
- - "<"
|
|
34
|
-
- !ruby/object:Gem::Version
|
|
35
|
-
version: '9'
|
|
36
|
-
type: :runtime
|
|
37
|
-
prerelease: false
|
|
38
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
39
|
-
requirements:
|
|
40
|
-
- - ">="
|
|
41
|
-
- !ruby/object:Gem::Version
|
|
42
|
-
version: '7.2'
|
|
43
|
-
- - "<"
|
|
44
|
-
- !ruby/object:Gem::Version
|
|
45
|
-
version: '9'
|
|
46
26
|
- !ruby/object:Gem::Dependency
|
|
47
27
|
name: textfsm
|
|
48
28
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -159,6 +139,26 @@ dependencies:
|
|
|
159
139
|
- - "~>"
|
|
160
140
|
- !ruby/object:Gem::Version
|
|
161
141
|
version: '2.0'
|
|
142
|
+
- !ruby/object:Gem::Dependency
|
|
143
|
+
name: logger
|
|
144
|
+
requirement: !ruby/object:Gem::Requirement
|
|
145
|
+
requirements:
|
|
146
|
+
- - ">="
|
|
147
|
+
- !ruby/object:Gem::Version
|
|
148
|
+
version: '1.5'
|
|
149
|
+
- - "<"
|
|
150
|
+
- !ruby/object:Gem::Version
|
|
151
|
+
version: '2.0'
|
|
152
|
+
type: :runtime
|
|
153
|
+
prerelease: false
|
|
154
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
155
|
+
requirements:
|
|
156
|
+
- - ">="
|
|
157
|
+
- !ruby/object:Gem::Version
|
|
158
|
+
version: '1.5'
|
|
159
|
+
- - "<"
|
|
160
|
+
- !ruby/object:Gem::Version
|
|
161
|
+
version: '2.0'
|
|
162
162
|
- !ruby/object:Gem::Dependency
|
|
163
163
|
name: net-http
|
|
164
164
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -373,8 +373,7 @@ dependencies:
|
|
|
373
373
|
- - "<"
|
|
374
374
|
- !ruby/object:Gem::Version
|
|
375
375
|
version: '1.0'
|
|
376
|
-
description:
|
|
377
|
-
interactive prompts, redacted logging, and Netdisco inventory backups.
|
|
376
|
+
description: 通过 SSH 或 Telnet 登录网络设备,采集配置、执行命令脚本、处理交互提示,并提供脱敏日志与基于 Netdisco 清单的批量备份。
|
|
378
377
|
executables:
|
|
379
378
|
- net-connector-backup
|
|
380
379
|
extensions: []
|
|
@@ -393,6 +392,7 @@ files:
|
|
|
393
392
|
- lib/net/connector/device/interface_description.rb
|
|
394
393
|
- lib/net/connector/device/interface_name.rb
|
|
395
394
|
- lib/net/connector/device/profile.rb
|
|
395
|
+
- lib/net/connector/device/profile/builder.rb
|
|
396
396
|
- lib/net/connector/device/running_config.rb
|
|
397
397
|
- lib/net/connector/device/running_config/strategy.rb
|
|
398
398
|
- lib/net/connector/engine.rb
|
|
@@ -419,6 +419,7 @@ files:
|
|
|
419
419
|
- lib/net/connector/netdisco/config_file.rb
|
|
420
420
|
- lib/net/connector/netdisco/device.rb
|
|
421
421
|
- lib/net/connector/netdisco/fleet.rb
|
|
422
|
+
- lib/net/connector/netdisco/plan.rb
|
|
422
423
|
- lib/net/connector/netdisco/planner.rb
|
|
423
424
|
- lib/net/connector/netdisco/result_store.rb
|
|
424
425
|
- lib/net/connector/netdisco/rules.rb
|
|
@@ -436,6 +437,7 @@ files:
|
|
|
436
437
|
- lib/net/connector/operations/saved_config.rb
|
|
437
438
|
- lib/net/connector/operations/tftp/cisco_ios.rb
|
|
438
439
|
- lib/net/connector/operations/tftp/cisco_nxos.rb
|
|
440
|
+
- lib/net/connector/operations/tftp/file_upload.rb
|
|
439
441
|
- lib/net/connector/operations/tftp/h3c.rb
|
|
440
442
|
- lib/net/connector/operations/tftp/hillstone.rb
|
|
441
443
|
- lib/net/connector/operations/tftp/huawei.rb
|
|
@@ -513,5 +515,5 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
513
515
|
requirements: []
|
|
514
516
|
rubygems_version: 4.0.12
|
|
515
517
|
specification_version: 4
|
|
516
|
-
summary:
|
|
518
|
+
summary: 网络设备命令行会话与 Netdisco 清单批量备份
|
|
517
519
|
test_files: []
|