net-connector 0.4.2 → 0.6.0
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 +23 -1
- data/README.md +92 -20
- data/docs/VERIFICATION.md +17 -7
- data/docs/architecture.md +102 -64
- data/examples/netdisco_database.yml +16 -0
- data/lib/net/connector/device/base.rb +27 -107
- data/lib/net/connector/device/local_backup.rb +96 -0
- data/lib/net/connector/device/profile.rb +8 -3
- data/lib/net/connector/device/running_config/strategy.rb +1 -1
- data/lib/net/connector/device/running_config.rb +44 -5
- data/lib/net/connector/device/save_config.rb +21 -0
- data/lib/net/connector/device/tftp/file_upload.rb +53 -0
- data/lib/net/connector/{operations/tftp_receipt.rb → device/tftp/receipt.rb} +18 -20
- data/lib/net/connector/device/tftp/strategy.rb +67 -0
- data/lib/net/connector/device/tftp/target.rb +63 -0
- data/lib/net/connector/device/tftp.rb +117 -0
- data/lib/net/connector/device/topology/immediate_strategy.rb +40 -0
- data/lib/net/connector/device/topology/interface_description.rb +46 -0
- data/lib/net/connector/device/topology/interface_name.rb +58 -0
- data/lib/net/connector/device/topology/strategy.rb +75 -0
- data/lib/net/connector/device/topology.rb +277 -0
- data/lib/net/connector/engine/authentication.rb +2 -2
- data/lib/net/connector/engine/configuration.rb +1 -1
- data/lib/net/connector/engine/dialogue.rb +21 -21
- data/lib/net/connector/engine/error_metadata.rb +50 -0
- data/lib/net/connector/engine/errors.rb +15 -1
- data/lib/net/connector/engine/execution.rb +17 -10
- data/lib/net/connector/engine/log/event.rb +66 -0
- data/lib/net/connector/engine/log/formatter.rb +16 -0
- data/lib/net/connector/engine/log/messages.rb +52 -0
- data/lib/net/connector/engine/log/stream.rb +56 -0
- data/lib/net/connector/engine/log.rb +105 -84
- data/lib/net/connector/engine/session.rb +83 -42
- data/lib/net/connector/engine/terminal_text.rb +33 -0
- data/lib/net/connector/engine/transport.rb +2 -2
- data/lib/net/connector/netdisco/batch.rb +9 -45
- data/lib/net/connector/netdisco/cli.rb +17 -10
- data/lib/net/connector/netdisco/client.rb +4 -3
- data/lib/net/connector/netdisco/config_file.rb +6 -3
- data/lib/net/connector/netdisco/database_client.rb +197 -0
- data/lib/net/connector/netdisco/device.rb +4 -5
- data/lib/net/connector/netdisco/diagnostic.rb +9 -39
- data/lib/net/connector/netdisco/fleet.rb +26 -39
- data/lib/net/connector/netdisco/report.rb +37 -16
- data/lib/net/connector/netdisco/result_store.rb +2 -2
- data/lib/net/connector/netdisco/settings.rb +26 -9
- data/lib/net/connector/netdisco.rb +1 -0
- data/lib/net/connector/{operations → storage}/backup_lock.rb +2 -2
- data/lib/net/connector/{operations → storage}/private_file.rb +2 -7
- data/lib/net/connector/{operations → storage}/safe_file.rb +1 -1
- data/lib/net/connector/{operations → storage}/saved_config.rb +10 -35
- data/lib/net/connector/storage.rb +15 -0
- data/lib/net/connector/textfsm.rb +72 -0
- data/lib/net/connector/vendor/cisco_ios/tftp_backup.rb +3 -3
- data/lib/net/connector/vendor/cisco_ios/topology.rb +5 -5
- data/lib/net/connector/vendor/cisco_nxos/tftp_backup.rb +3 -3
- data/lib/net/connector/vendor/h3c/tftp_backup.rb +4 -4
- data/lib/net/connector/vendor/h3c/topology.rb +5 -5
- data/lib/net/connector/vendor/h3c.rb +3 -3
- data/lib/net/connector/vendor/hillstone/tftp_backup.rb +3 -3
- data/lib/net/connector/vendor/hillstone/topology.rb +5 -5
- data/lib/net/connector/vendor/huawei/tftp_backup.rb +3 -3
- data/lib/net/connector/vendor/palo_alto/running_config.rb +1 -1
- data/lib/net/connector/vendor/palo_alto/tftp_backup.rb +3 -3
- data/lib/net/connector/vendor/palo_alto/topology.rb +3 -6
- data/lib/net/connector/vendor/radware/tftp_backup.rb +3 -3
- data/lib/net/connector/vendor/radware/topology.rb +2 -2
- data/lib/net/connector/version.rb +1 -1
- data/lib/net/connector.rb +1 -6
- metadata +47 -39
- data/lib/net/connector/device/interface_description.rb +0 -44
- data/lib/net/connector/device/interface_name.rb +0 -56
- data/lib/net/connector/engine/base.rb +0 -4
- data/lib/net/connector/engine/log_messages.rb +0 -47
- data/lib/net/connector/engine/profile.rb +0 -4
- data/lib/net/connector/engine.rb +0 -4
- data/lib/net/connector/operations/local_backup.rb +0 -89
- data/lib/net/connector/operations/parse_output.rb +0 -77
- data/lib/net/connector/operations/running_config/cisco.rb +0 -14
- data/lib/net/connector/operations/running_config/hillstone.rb +0 -12
- data/lib/net/connector/operations/running_config/palo_alto.rb +0 -12
- data/lib/net/connector/operations/running_config/strategy.rb +0 -3
- data/lib/net/connector/operations/running_config.rb +0 -16
- data/lib/net/connector/operations/saved_config/legacy_index.rb +0 -109
- data/lib/net/connector/operations/tftp/cisco_ios.rb +0 -11
- data/lib/net/connector/operations/tftp/cisco_nxos.rb +0 -11
- data/lib/net/connector/operations/tftp/file_upload.rb +0 -55
- data/lib/net/connector/operations/tftp/h3c.rb +0 -11
- data/lib/net/connector/operations/tftp/hillstone.rb +0 -11
- data/lib/net/connector/operations/tftp/huawei.rb +0 -11
- data/lib/net/connector/operations/tftp/palo_alto.rb +0 -11
- data/lib/net/connector/operations/tftp/radware.rb +0 -11
- data/lib/net/connector/operations/tftp/strategy.rb +0 -75
- data/lib/net/connector/operations/tftp_backup.rb +0 -183
- data/lib/net/connector/operations/topology/cisco.rb +0 -11
- data/lib/net/connector/operations/topology/h3c.rb +0 -11
- data/lib/net/connector/operations/topology/hillstone.rb +0 -11
- data/lib/net/connector/operations/topology/immediate_strategy.rb +0 -45
- data/lib/net/connector/operations/topology/palo_alto.rb +0 -11
- data/lib/net/connector/operations/topology/radware.rb +0 -11
- data/lib/net/connector/operations/topology/strategy.rb +0 -87
- data/lib/net/connector/operations/topology.rb +0 -261
- data/lib/net/connector/operations.rb +0 -26
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require_relative "../../
|
|
3
|
+
require_relative "../../device/topology/strategy"
|
|
4
4
|
|
|
5
5
|
module Net
|
|
6
6
|
module Connector
|
|
7
7
|
module Radware
|
|
8
|
-
class Topology <
|
|
8
|
+
class Topology < Topology::Strategy
|
|
9
9
|
# Alteon 只支持读取端口描述,不提供邻居发现或自动改写。
|
|
10
10
|
def self.supports?(capability) = capability == :interface_descriptions
|
|
11
11
|
|
data/lib/net/connector.rb
CHANGED
|
@@ -16,18 +16,13 @@ module Net
|
|
|
16
16
|
hillstone: "Hillstone"
|
|
17
17
|
}.freeze
|
|
18
18
|
|
|
19
|
-
ALIASES = {
|
|
20
|
-
"cisco_n9k" => :cisco_nxos,
|
|
21
|
-
"paloalto" => :palo_alto
|
|
22
|
-
}.freeze
|
|
23
|
-
|
|
24
19
|
# 返回当前支持的厂商标识集合。
|
|
25
20
|
def self.vendors = VENDORS.keys
|
|
26
21
|
|
|
27
22
|
# 根据厂商标识查找连接器类。
|
|
28
23
|
def self.vendor_class(vendor)
|
|
29
24
|
key = vendor.to_s.downcase.tr(" -", "__")
|
|
30
|
-
key =
|
|
25
|
+
key = key.to_sym
|
|
31
26
|
name = VENDORS.fetch(key) { raise ArgumentError, "unsupported vendor: #{vendor.inspect}" }
|
|
32
27
|
require_relative "connector/vendor/#{key}"
|
|
33
28
|
const_get(name, false).const_get(:Connector, false)
|
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
|
+
version: 0.6.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- net-connector contributors
|
|
@@ -37,6 +37,26 @@ dependencies:
|
|
|
37
37
|
- - "~>"
|
|
38
38
|
- !ruby/object:Gem::Version
|
|
39
39
|
version: 0.2.0
|
|
40
|
+
- !ruby/object:Gem::Dependency
|
|
41
|
+
name: pg
|
|
42
|
+
requirement: !ruby/object:Gem::Requirement
|
|
43
|
+
requirements:
|
|
44
|
+
- - ">="
|
|
45
|
+
- !ruby/object:Gem::Version
|
|
46
|
+
version: '1.5'
|
|
47
|
+
- - "<"
|
|
48
|
+
- !ruby/object:Gem::Version
|
|
49
|
+
version: '2.0'
|
|
50
|
+
type: :runtime
|
|
51
|
+
prerelease: false
|
|
52
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
53
|
+
requirements:
|
|
54
|
+
- - ">="
|
|
55
|
+
- !ruby/object:Gem::Version
|
|
56
|
+
version: '1.5'
|
|
57
|
+
- - "<"
|
|
58
|
+
- !ruby/object:Gem::Version
|
|
59
|
+
version: '2.0'
|
|
40
60
|
- !ruby/object:Gem::Dependency
|
|
41
61
|
name: digest
|
|
42
62
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -407,38 +427,52 @@ files:
|
|
|
407
427
|
- docs/RELEASING.md
|
|
408
428
|
- docs/VERIFICATION.md
|
|
409
429
|
- docs/architecture.md
|
|
430
|
+
- examples/netdisco_database.yml
|
|
410
431
|
- exe/net-connector-backup
|
|
411
432
|
- lib/net-connector.rb
|
|
412
433
|
- lib/net/connector.rb
|
|
413
434
|
- lib/net/connector/device/base.rb
|
|
414
|
-
- lib/net/connector/device/
|
|
415
|
-
- lib/net/connector/device/interface_name.rb
|
|
435
|
+
- lib/net/connector/device/local_backup.rb
|
|
416
436
|
- lib/net/connector/device/profile.rb
|
|
417
437
|
- lib/net/connector/device/profile/builder.rb
|
|
418
438
|
- lib/net/connector/device/running_config.rb
|
|
419
439
|
- lib/net/connector/device/running_config/strategy.rb
|
|
420
|
-
- lib/net/connector/
|
|
440
|
+
- lib/net/connector/device/save_config.rb
|
|
441
|
+
- lib/net/connector/device/tftp.rb
|
|
442
|
+
- lib/net/connector/device/tftp/file_upload.rb
|
|
443
|
+
- lib/net/connector/device/tftp/receipt.rb
|
|
444
|
+
- lib/net/connector/device/tftp/strategy.rb
|
|
445
|
+
- lib/net/connector/device/tftp/target.rb
|
|
446
|
+
- lib/net/connector/device/topology.rb
|
|
447
|
+
- lib/net/connector/device/topology/immediate_strategy.rb
|
|
448
|
+
- lib/net/connector/device/topology/interface_description.rb
|
|
449
|
+
- lib/net/connector/device/topology/interface_name.rb
|
|
450
|
+
- lib/net/connector/device/topology/strategy.rb
|
|
421
451
|
- lib/net/connector/engine/authentication.rb
|
|
422
|
-
- lib/net/connector/engine/base.rb
|
|
423
452
|
- lib/net/connector/engine/command.rb
|
|
424
453
|
- lib/net/connector/engine/configuration.rb
|
|
425
454
|
- lib/net/connector/engine/core.rb
|
|
426
455
|
- lib/net/connector/engine/dialogue.rb
|
|
456
|
+
- lib/net/connector/engine/error_metadata.rb
|
|
427
457
|
- lib/net/connector/engine/errors.rb
|
|
428
458
|
- lib/net/connector/engine/execution.rb
|
|
429
459
|
- lib/net/connector/engine/log.rb
|
|
430
|
-
- lib/net/connector/engine/
|
|
431
|
-
- lib/net/connector/engine/
|
|
460
|
+
- lib/net/connector/engine/log/event.rb
|
|
461
|
+
- lib/net/connector/engine/log/formatter.rb
|
|
462
|
+
- lib/net/connector/engine/log/messages.rb
|
|
463
|
+
- lib/net/connector/engine/log/stream.rb
|
|
432
464
|
- lib/net/connector/engine/recovery.rb
|
|
433
465
|
- lib/net/connector/engine/result.rb
|
|
434
466
|
- lib/net/connector/engine/session.rb
|
|
435
467
|
- lib/net/connector/engine/terminal_renderer.rb
|
|
468
|
+
- lib/net/connector/engine/terminal_text.rb
|
|
436
469
|
- lib/net/connector/engine/transport.rb
|
|
437
470
|
- lib/net/connector/netdisco.rb
|
|
438
471
|
- lib/net/connector/netdisco/batch.rb
|
|
439
472
|
- lib/net/connector/netdisco/cli.rb
|
|
440
473
|
- lib/net/connector/netdisco/client.rb
|
|
441
474
|
- lib/net/connector/netdisco/config_file.rb
|
|
475
|
+
- lib/net/connector/netdisco/database_client.rb
|
|
442
476
|
- lib/net/connector/netdisco/device.rb
|
|
443
477
|
- lib/net/connector/netdisco/diagnostic.rb
|
|
444
478
|
- lib/net/connector/netdisco/fleet.rb
|
|
@@ -450,38 +484,11 @@ files:
|
|
|
450
484
|
- lib/net/connector/netdisco/rules.rb
|
|
451
485
|
- lib/net/connector/netdisco/settings.rb
|
|
452
486
|
- lib/net/connector/netdisco/worker.rb
|
|
453
|
-
- lib/net/connector/
|
|
454
|
-
- lib/net/connector/
|
|
455
|
-
- lib/net/connector/
|
|
456
|
-
- lib/net/connector/
|
|
457
|
-
- lib/net/connector/
|
|
458
|
-
- lib/net/connector/operations/running_config.rb
|
|
459
|
-
- lib/net/connector/operations/running_config/cisco.rb
|
|
460
|
-
- lib/net/connector/operations/running_config/hillstone.rb
|
|
461
|
-
- lib/net/connector/operations/running_config/palo_alto.rb
|
|
462
|
-
- lib/net/connector/operations/running_config/strategy.rb
|
|
463
|
-
- lib/net/connector/operations/safe_file.rb
|
|
464
|
-
- lib/net/connector/operations/saved_config.rb
|
|
465
|
-
- lib/net/connector/operations/saved_config/legacy_index.rb
|
|
466
|
-
- lib/net/connector/operations/tftp/cisco_ios.rb
|
|
467
|
-
- lib/net/connector/operations/tftp/cisco_nxos.rb
|
|
468
|
-
- lib/net/connector/operations/tftp/file_upload.rb
|
|
469
|
-
- lib/net/connector/operations/tftp/h3c.rb
|
|
470
|
-
- lib/net/connector/operations/tftp/hillstone.rb
|
|
471
|
-
- lib/net/connector/operations/tftp/huawei.rb
|
|
472
|
-
- lib/net/connector/operations/tftp/palo_alto.rb
|
|
473
|
-
- lib/net/connector/operations/tftp/radware.rb
|
|
474
|
-
- lib/net/connector/operations/tftp/strategy.rb
|
|
475
|
-
- lib/net/connector/operations/tftp_backup.rb
|
|
476
|
-
- lib/net/connector/operations/tftp_receipt.rb
|
|
477
|
-
- lib/net/connector/operations/topology.rb
|
|
478
|
-
- lib/net/connector/operations/topology/cisco.rb
|
|
479
|
-
- lib/net/connector/operations/topology/h3c.rb
|
|
480
|
-
- lib/net/connector/operations/topology/hillstone.rb
|
|
481
|
-
- lib/net/connector/operations/topology/immediate_strategy.rb
|
|
482
|
-
- lib/net/connector/operations/topology/palo_alto.rb
|
|
483
|
-
- lib/net/connector/operations/topology/radware.rb
|
|
484
|
-
- lib/net/connector/operations/topology/strategy.rb
|
|
487
|
+
- lib/net/connector/storage.rb
|
|
488
|
+
- lib/net/connector/storage/backup_lock.rb
|
|
489
|
+
- lib/net/connector/storage/private_file.rb
|
|
490
|
+
- lib/net/connector/storage/safe_file.rb
|
|
491
|
+
- lib/net/connector/storage/saved_config.rb
|
|
485
492
|
- lib/net/connector/templates/cisco_cdp_neighbors_detail.textfsm
|
|
486
493
|
- lib/net/connector/templates/cisco_ios_running_config_interfaces.textfsm
|
|
487
494
|
- lib/net/connector/templates/cisco_ios_show_ip_interface_brief.textfsm
|
|
@@ -494,6 +501,7 @@ files:
|
|
|
494
501
|
- lib/net/connector/templates/palo_alto_interface_descriptions.textfsm
|
|
495
502
|
- lib/net/connector/templates/palo_alto_lldp_neighbors.textfsm
|
|
496
503
|
- lib/net/connector/templates/radware_port_names.textfsm
|
|
504
|
+
- lib/net/connector/textfsm.rb
|
|
497
505
|
- lib/net/connector/vendor/cisco_ios.rb
|
|
498
506
|
- lib/net/connector/vendor/cisco_ios/running_config.rb
|
|
499
507
|
- lib/net/connector/vendor/cisco_ios/tftp_backup.rb
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require_relative "interface_name"
|
|
4
|
-
|
|
5
|
-
module Net
|
|
6
|
-
module Connector
|
|
7
|
-
# 描述文本与常见接口视图命令的纯构造方法,不连接或修改设备。
|
|
8
|
-
module InterfaceDescription
|
|
9
|
-
# 将邻居名称和接口拼成默认描述;只缩写邻居接口,保留原始大小写。
|
|
10
|
-
def self.format(neighbor, abbreviate: true, lowercase: false)
|
|
11
|
-
port = if abbreviate
|
|
12
|
-
InterfaceName.short(neighbor.neighbor_interface, lowercase: lowercase)
|
|
13
|
-
else
|
|
14
|
-
lowercase ? neighbor.neighbor_interface.downcase : neighbor.neighbor_interface
|
|
15
|
-
end
|
|
16
|
-
validate!("To #{neighbor.neighbor_name} #{port}")
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
# 生成进入接口、设置描述和退出视图的命令,不执行设备操作。
|
|
20
|
-
def self.commands(interface:, description:, leave: "exit")
|
|
21
|
-
validate_interface!(interface)
|
|
22
|
-
validate!(description)
|
|
23
|
-
raise ArgumentError, "interface exit must be exit or quit" unless %w[exit quit].include?(leave)
|
|
24
|
-
|
|
25
|
-
["interface #{interface}", "description #{description}", leave]
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
# 共享的输入约束同样适用于 PAN-OS 的独立命令语法。
|
|
29
|
-
def self.validate!(value)
|
|
30
|
-
return value if value.is_a?(String) && value.bytesize.between?(1, 80) &&
|
|
31
|
-
value.match?(/\A[\p{Alnum}_.: \/-]+\z/u)
|
|
32
|
-
|
|
33
|
-
raise ArgumentError, "description must be 1-80 bytes of plain interface text"
|
|
34
|
-
end
|
|
35
|
-
|
|
36
|
-
# 拒绝可能把描述命令拆成多条命令的不安全接口名。
|
|
37
|
-
def self.validate_interface!(value)
|
|
38
|
-
return value if value.is_a?(String) && value.match?(/\A[A-Za-z][A-Za-z0-9.\/-]*\z/)
|
|
39
|
-
|
|
40
|
-
raise ArgumentError, "neighbor interface name is unsafe"
|
|
41
|
-
end
|
|
42
|
-
end
|
|
43
|
-
end
|
|
44
|
-
end
|
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Net
|
|
4
|
-
module Connector
|
|
5
|
-
# 接口身份匹配与描述展示共用名称规则;展示简称不能直接用作下发命令。
|
|
6
|
-
module InterfaceName
|
|
7
|
-
RULES = [
|
|
8
|
-
[/\A(?:xge|ten-gigabitethernet|tengigabitethernet|te)(?=\d)/i, "tengigabitethernet", "Te"],
|
|
9
|
-
[/\A(?:gigabitethernet|ge|gi)(?=\d)/i, "gigabitethernet", "Gi"],
|
|
10
|
-
[/\A(?:fastethernet|fa)(?=\d)/i, "fastethernet", "Fa"],
|
|
11
|
-
[/\A(?:ethernet|eth)(?=\d)/i, "ethernet", "Eth"],
|
|
12
|
-
[/\A(?:port-channel|po)(?=\d)/i, "port-channel", "Po"]
|
|
13
|
-
].map(&:freeze).freeze
|
|
14
|
-
|
|
15
|
-
# 用于本机邻居表与配置的关联;保留已有证据键的拼写契约。
|
|
16
|
-
def self.key(name)
|
|
17
|
-
rule = RULES.find { |pattern, _key, _short| pattern.match?(name) }
|
|
18
|
-
rule ? name.sub(rule.first, rule[1]).downcase : name.downcase
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
# 仅缩短已识别的前缀,保留端口、子接口编号及未知命名。
|
|
22
|
-
# 默认延续输入的大写、小写或首字母大写形式;统一小写由调用方选择。
|
|
23
|
-
def self.short(name, lowercase: false)
|
|
24
|
-
rule = RULES.find { |pattern, _key, _short| pattern.match?(name) }
|
|
25
|
-
formatted = if rule
|
|
26
|
-
name.sub(rule.first) do |prefix|
|
|
27
|
-
abbreviation = rule.last
|
|
28
|
-
if prefix == prefix.downcase
|
|
29
|
-
abbreviation.downcase
|
|
30
|
-
elsif prefix == prefix.upcase
|
|
31
|
-
abbreviation.upcase
|
|
32
|
-
elsif prefix.casecmp?(abbreviation)
|
|
33
|
-
prefix
|
|
34
|
-
else
|
|
35
|
-
abbreviation
|
|
36
|
-
end
|
|
37
|
-
end
|
|
38
|
-
else
|
|
39
|
-
name.dup
|
|
40
|
-
end
|
|
41
|
-
lowercase ? formatted.downcase : formatted
|
|
42
|
-
end
|
|
43
|
-
|
|
44
|
-
# 保留现有配置视图展开规则;厂商策略可覆盖不适用的名称。
|
|
45
|
-
def self.configuration(name)
|
|
46
|
-
name.sub(/\AXGE(?=\d)/i, "Ten-GigabitEthernet")
|
|
47
|
-
.sub(/\AGE(?=\d)/i, "GigabitEthernet")
|
|
48
|
-
.sub(/\AGi(?=\d)/i, "GigabitEthernet")
|
|
49
|
-
.sub(/\ATe(?=\d)/i, "TenGigabitEthernet")
|
|
50
|
-
.sub(/\AFa(?=\d)/i, "FastEthernet")
|
|
51
|
-
.sub(/\AEth(?=\d)/i, "Ethernet")
|
|
52
|
-
.sub(/\APo(?=\d)/i, "port-channel")
|
|
53
|
-
end
|
|
54
|
-
end
|
|
55
|
-
end
|
|
56
|
-
end
|
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Net
|
|
4
|
-
module Connector
|
|
5
|
-
# 独立于日志目标的人类可读事件文案。
|
|
6
|
-
module LogMessages
|
|
7
|
-
module_function
|
|
8
|
-
|
|
9
|
-
# 将结构化会话事件转换为便于人工阅读的中文日志。
|
|
10
|
-
def format(name, fields)
|
|
11
|
-
case name
|
|
12
|
-
when "connect"
|
|
13
|
-
"开始连接 #{fields[:host]}(#{fields[:protocol].to_s.upcase},账号 #{fields[:username]})"
|
|
14
|
-
when "connect_failed"
|
|
15
|
-
"连接失败:#{fields[:message]}(#{fields[:error]})"
|
|
16
|
-
when "login_start"
|
|
17
|
-
"等待设备登录提示"
|
|
18
|
-
when "login_output"
|
|
19
|
-
"登录过程回显(已脱敏):"
|
|
20
|
-
when "login_complete"
|
|
21
|
-
fields[:status] == "ok" ? "登录成功,设备提示符:#{fields[:prompt]}" :
|
|
22
|
-
"登录失败:#{fields[:message]}(#{fields[:error]})"
|
|
23
|
-
when "command_start"
|
|
24
|
-
"下发命令:#{fields[:text]}"
|
|
25
|
-
when "device_output"
|
|
26
|
-
"设备回显:"
|
|
27
|
-
when "command_complete"
|
|
28
|
-
fields[:status] == "response_received" ? "命令回显结束,已收到设备提示符" :
|
|
29
|
-
"命令执行失败:#{fields[:message]}(#{fields[:error]})"
|
|
30
|
-
when "command_detail"
|
|
31
|
-
"命令耗时 #{fields[:duration_ms]} 毫秒,收到 #{fields[:response_bytes]} 字节回显"
|
|
32
|
-
when "tftp_backup"
|
|
33
|
-
case fields[:status]
|
|
34
|
-
when "reported_uploaded"
|
|
35
|
-
"TFTP 备份:设备报告上传成功,目标 #{fields[:server]}/#{fields[:path]};服务器文件尚未核验"
|
|
36
|
-
when "transfer_failed"
|
|
37
|
-
"TFTP 备份失败:设备报告传输失败,服务器 #{fields[:server]}"
|
|
38
|
-
else
|
|
39
|
-
"TFTP 备份未确认:设备未报告上传成功,服务器 #{fields[:server]}"
|
|
40
|
-
end
|
|
41
|
-
else
|
|
42
|
-
name.to_s
|
|
43
|
-
end
|
|
44
|
-
end
|
|
45
|
-
end
|
|
46
|
-
end
|
|
47
|
-
end
|
data/lib/net/connector/engine.rb
DELETED
|
@@ -1,89 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require "digest"
|
|
4
|
-
require_relative "private_file"
|
|
5
|
-
require_relative "backup_lock"
|
|
6
|
-
require_relative "safe_file"
|
|
7
|
-
|
|
8
|
-
module Net
|
|
9
|
-
module Connector
|
|
10
|
-
Backup = Data.define(:path, :bytes, :sha256, :collected_at, :change, :previous_sha256) do
|
|
11
|
-
# 保存配置备份的路径、摘要和变更状态。
|
|
12
|
-
def initialize(path:, bytes:, sha256:, collected_at:, change: nil, previous_sha256: nil)
|
|
13
|
-
super
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
# 判断本次采集是否产生新的配置内容。
|
|
17
|
-
def changed? = [:created, :changed].include?(change)
|
|
18
|
-
end
|
|
19
|
-
|
|
20
|
-
# 只携带库自身的提交回执和配置元数据,不携带正文或原始文件系统异常。
|
|
21
|
-
class BackupPersistenceError < Error
|
|
22
|
-
attr_reader :backup, :receipt, :underlying_type
|
|
23
|
-
|
|
24
|
-
def initialize(backup:, write_error:, host: nil)
|
|
25
|
-
unless backup.instance_of?(Backup) && Operations::PrivateFile.receipt_error?(write_error) &&
|
|
26
|
-
write_error.receipt.committed? && write_error.receipt.path == backup.path
|
|
27
|
-
raise ArgumentError, "backup persistence error requires a matching committed backup receipt"
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
@backup, @receipt = backup, write_error.receipt
|
|
31
|
-
@underlying_type = write_error.underlying_type
|
|
32
|
-
code = if write_error.instance_of?(Operations::PrivateFile::DirectorySyncUnsupported)
|
|
33
|
-
:backup_durability_unsupported
|
|
34
|
-
elsif receipt.durable?
|
|
35
|
-
:backup_finalize_failed
|
|
36
|
-
else
|
|
37
|
-
:backup_persistence_unconfirmed
|
|
38
|
-
end
|
|
39
|
-
super(write_error.message, code: code, host: host, phase: :backup)
|
|
40
|
-
end
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
module Operations
|
|
44
|
-
class LocalBackup
|
|
45
|
-
# 保存执行配置采集的设备对象。
|
|
46
|
-
def initialize(device) = @device = device
|
|
47
|
-
|
|
48
|
-
# 采集配置、识别变更并原子写入私有文件。
|
|
49
|
-
def call(path:, lock_timeout: 0)
|
|
50
|
-
host = @device.host if @device.respond_to?(:host)
|
|
51
|
-
BackupLock.synchronize(path, timeout: lock_timeout, host: host) { |lock| collect_and_write(lock.path) }
|
|
52
|
-
end
|
|
53
|
-
|
|
54
|
-
private
|
|
55
|
-
|
|
56
|
-
def collect_and_write(destination)
|
|
57
|
-
contents = @device.running_config.value!
|
|
58
|
-
digest = Digest::SHA256.hexdigest(contents)
|
|
59
|
-
previous = SafeFile.fingerprint(destination, missing: true, replace_symlink: true)
|
|
60
|
-
previous_digest = previous&.sha256
|
|
61
|
-
change = if previous_digest.nil?
|
|
62
|
-
:created
|
|
63
|
-
elsif previous_digest == digest
|
|
64
|
-
:unchanged
|
|
65
|
-
else
|
|
66
|
-
:changed
|
|
67
|
-
end
|
|
68
|
-
|
|
69
|
-
backup = Backup.new(path: destination, bytes: contents.bytesize,
|
|
70
|
-
sha256: digest, collected_at: Time.now.utc, change: change,
|
|
71
|
-
previous_sha256: previous_digest)
|
|
72
|
-
if change != :unchanged || previous.mode != 0o600 || !SafeFile.same_entry?(destination, previous)
|
|
73
|
-
write_backup(backup, contents)
|
|
74
|
-
end
|
|
75
|
-
backup
|
|
76
|
-
end
|
|
77
|
-
|
|
78
|
-
def write_backup(backup, contents)
|
|
79
|
-
PrivateFile.write_receipt(backup.path, contents)
|
|
80
|
-
rescue PrivateFile::WriteError => error
|
|
81
|
-
raise unless PrivateFile.receipt_error?(error) && error.receipt.committed?
|
|
82
|
-
|
|
83
|
-
host = @device.host if @device.respond_to?(:host)
|
|
84
|
-
raise BackupPersistenceError.new(backup: backup, write_error: error, host: host), cause: nil
|
|
85
|
-
end
|
|
86
|
-
end
|
|
87
|
-
end
|
|
88
|
-
end
|
|
89
|
-
end
|
|
@@ -1,77 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require "textfsm"
|
|
4
|
-
require_relative "../engine/errors"
|
|
5
|
-
require_relative "../engine/terminal_renderer"
|
|
6
|
-
|
|
7
|
-
module Net
|
|
8
|
-
module Connector
|
|
9
|
-
module Operations
|
|
10
|
-
# 将设备命令回显或配置文本按 TextFSM 模板转换为结构化记录。
|
|
11
|
-
class ParseOutput
|
|
12
|
-
DEFAULT_TEMPLATE_DIR = File.expand_path("../templates", __dir__).freeze
|
|
13
|
-
|
|
14
|
-
# 配置模板目录和 Netmiko 风格的命令索引文件。
|
|
15
|
-
def initialize(template_dir: nil, index: "index")
|
|
16
|
-
template_dir ||= DEFAULT_TEMPLATE_DIR
|
|
17
|
-
raise ArgumentError, "template_dir must be a nonempty String" unless template_dir.is_a?(String) && !template_dir.empty?
|
|
18
|
-
raise ArgumentError, "index must be a nonempty String" unless index.is_a?(String) && !index.empty?
|
|
19
|
-
|
|
20
|
-
@template_dir = File.expand_path(template_dir)
|
|
21
|
-
@index = index
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
# 解析按 UTF-8 字节处理副本,先验证原文,避免回车或转义序列隐藏非法字节。
|
|
25
|
-
# 拓扑选模板和计数也使用这份副本,但仍保留未经终端渲染的完整证据。
|
|
26
|
-
def utf8(text, host: nil)
|
|
27
|
-
raise ArgumentError, "text must be a String" unless text.is_a?(String)
|
|
28
|
-
|
|
29
|
-
text = text.b.force_encoding(Encoding::UTF_8)
|
|
30
|
-
invalid_encoding!(host) unless text.valid_encoding?
|
|
31
|
-
text
|
|
32
|
-
end
|
|
33
|
-
|
|
34
|
-
# 显式模板按路径读取;未指定时按厂商和命令从索引选择模板。
|
|
35
|
-
def call(text, template: nil, vendor: nil, command: nil, host: nil)
|
|
36
|
-
text = TerminalRenderer.render(utf8(text, host: host), strict_utf8: true).force_encoding(Encoding::UTF_8)
|
|
37
|
-
if template
|
|
38
|
-
raise ArgumentError, "template must be a nonempty String" unless template.is_a?(String) && !template.empty?
|
|
39
|
-
|
|
40
|
-
TextFSM::Parser.from_file(File.expand_path(template, @template_dir)).parse_hashes(text)
|
|
41
|
-
else
|
|
42
|
-
raise ArgumentError, "vendor and command are required for template lookup" unless vendor && command.is_a?(String) && !command.empty?
|
|
43
|
-
|
|
44
|
-
attributes = { "Vendor" => vendor.to_s, "Command" => command }
|
|
45
|
-
table = TextFSM::CliTable.new(index: @index, template_dir: @template_dir)
|
|
46
|
-
unless table.index.match(attributes)
|
|
47
|
-
raise ParsingError.new("no TextFSM template matches this vendor and command",
|
|
48
|
-
code: :template_missing, host: host, phase: :parse)
|
|
49
|
-
end
|
|
50
|
-
table.parse(text, attributes: attributes).to_hashes
|
|
51
|
-
end
|
|
52
|
-
rescue Encoding::InvalidByteSequenceError
|
|
53
|
-
invalid_encoding!(host)
|
|
54
|
-
rescue TextFSM::IndexError
|
|
55
|
-
raise ParsingError.new("TextFSM template index is invalid",
|
|
56
|
-
code: :template_invalid, host: host, phase: :parse), cause: nil
|
|
57
|
-
rescue TextFSM::TemplateError
|
|
58
|
-
raise ParsingError.new("TextFSM template is invalid",
|
|
59
|
-
code: :template_invalid, host: host, phase: :parse), cause: nil
|
|
60
|
-
rescue TextFSM::ParseError
|
|
61
|
-
raise ParsingError.new("TextFSM could not parse the device output",
|
|
62
|
-
code: :parse_failed, host: host, phase: :parse), cause: nil
|
|
63
|
-
rescue IOError, SystemCallError
|
|
64
|
-
raise ParsingError.new("unable to read TextFSM template",
|
|
65
|
-
code: :template_unreadable, host: host, phase: :parse), cause: nil
|
|
66
|
-
end
|
|
67
|
-
|
|
68
|
-
private
|
|
69
|
-
|
|
70
|
-
def invalid_encoding!(host)
|
|
71
|
-
raise ParsingError.new("device output is not valid UTF-8", code: :invalid_output_encoding,
|
|
72
|
-
host: host, phase: :parse), cause: nil
|
|
73
|
-
end
|
|
74
|
-
end
|
|
75
|
-
end
|
|
76
|
-
end
|
|
77
|
-
end
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require_relative "../running_config"
|
|
4
|
-
require_relative "../../vendor/cisco_ios/running_config"
|
|
5
|
-
require_relative "../../vendor/cisco_nxos/running_config"
|
|
6
|
-
|
|
7
|
-
module Net
|
|
8
|
-
module Connector
|
|
9
|
-
module Operations
|
|
10
|
-
RunningConfig::Cisco = Net::Connector::CiscoIos::RunningConfig
|
|
11
|
-
RunningConfig::CiscoNxos = Net::Connector::CiscoNxos::RunningConfig
|
|
12
|
-
end
|
|
13
|
-
end
|
|
14
|
-
end
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require_relative "../running_config"
|
|
4
|
-
require_relative "../../vendor/hillstone/running_config"
|
|
5
|
-
|
|
6
|
-
module Net
|
|
7
|
-
module Connector
|
|
8
|
-
module Operations
|
|
9
|
-
RunningConfig::Hillstone = Net::Connector::Hillstone::RunningConfig
|
|
10
|
-
end
|
|
11
|
-
end
|
|
12
|
-
end
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require_relative "../running_config"
|
|
4
|
-
require_relative "../../vendor/palo_alto/running_config"
|
|
5
|
-
|
|
6
|
-
module Net
|
|
7
|
-
module Connector
|
|
8
|
-
module Operations
|
|
9
|
-
RunningConfig::PaloAlto = Net::Connector::PaloAlto::RunningConfig
|
|
10
|
-
end
|
|
11
|
-
end
|
|
12
|
-
end
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require_relative "../device/running_config"
|
|
4
|
-
|
|
5
|
-
module Net
|
|
6
|
-
module Connector
|
|
7
|
-
module Operations
|
|
8
|
-
# 旧常量与新能力共享同一实现,不维护第二套采集流程。
|
|
9
|
-
RunningConfig = Net::Connector::RunningConfig
|
|
10
|
-
RunningConfig.autoload :Cisco, File.expand_path("running_config/cisco", __dir__)
|
|
11
|
-
RunningConfig.autoload :CiscoNxos, File.expand_path("running_config/cisco", __dir__)
|
|
12
|
-
RunningConfig.autoload :Hillstone, File.expand_path("running_config/hillstone", __dir__)
|
|
13
|
-
RunningConfig.autoload :PaloAlto, File.expand_path("running_config/palo_alto", __dir__)
|
|
14
|
-
end
|
|
15
|
-
end
|
|
16
|
-
end
|