oxidized 0.16.3 → 0.17.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 +10 -0
- data/Dockerfile +1 -1
- data/Gemfile.lock +8 -6
- data/README.md +138 -76
- data/Rakefile +4 -4
- data/extra/rest_client.rb +25 -3
- data/lib/oxidized/input/ssh.rb +20 -11
- data/lib/oxidized/input/tftp.rb +41 -0
- data/lib/oxidized/model/alvarion +13 -0
- data/lib/oxidized/model/catos.rb +9 -2
- data/lib/oxidized/model/pfsense.rb +2 -11
- data/lib/oxidized/model/routeros.rb +2 -1
- data/lib/oxidized/node.rb +35 -17
- data/lib/oxidized/output/file.rb +8 -6
- data/lib/oxidized/source/csv.rb +5 -3
- data/lib/oxidized/source/http.rb +4 -2
- data/lib/oxidized/source/source.rb +12 -0
- data/lib/oxidized/source/sql.rb +3 -1
- data/lib/oxidized/version.rb +1 -1
- data/oxidized.gemspec +1 -1
- metadata +8 -12
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 4293285f8095f28f9f3d38dc2d606a03a58d163b
|
|
4
|
+
data.tar.gz: f108592ebdce488d10f06d7ee0e5545e3e117e32
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: aed22b16c6223c5b27a6b68476e25aea4154fcafd104a8567f7f19c4de38c8dddcd3fe18e1fd0950bc6e01e927d6af2fed514dd8f966eb33670f2a3517c6285f
|
|
7
|
+
data.tar.gz: 62a21f8caa39a27c853d2d56b3b96d35f6320db5cf6743ea76dd0cb7c6562729a0b96b5cc9b83524ad6edaac960dfb07ab88c7bffa526b459248603ba0e71bfa
|
data/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,13 @@
|
|
|
1
|
+
# 0 17.3
|
|
2
|
+
- FEATURE: "nil", "false" and "true" in source (e.g. router.db) are interpeted as nil, false, true. Empty is now always considered empty string, instead of in some cases nil and some cases empty string.
|
|
3
|
+
- FEATURE: support tftp as input model (@MajesticFalcon)
|
|
4
|
+
- FEATURE: add alvarion model (@MajesticFalcon)
|
|
5
|
+
- FEATURE: detect if ssh wants password terminal/CLI prompt or not
|
|
6
|
+
- FEATURE: node (group, model, username, password) resolution refactoring, supports wider range of use-cases
|
|
7
|
+
- BUGFIX: fetch for file output (@danilopopeye)
|
|
8
|
+
- BUGFIX: net-ssh version specification
|
|
9
|
+
- BUGFIX: routeros, catos, pfsense
|
|
10
|
+
|
|
1
11
|
# 0.16.3
|
|
2
12
|
- FEATURE: pfsense support (by @stokbaek)
|
|
3
13
|
- BUGFIX: cumulus prompt not working with default switch configs (by @nertwork)
|
data/Dockerfile
CHANGED
|
@@ -3,7 +3,7 @@ MAINTAINER Samer Abdel-Hafez <sam@arahant.net>
|
|
|
3
3
|
|
|
4
4
|
RUN add-apt-repository ppa:brightbox/ruby-ng && \
|
|
5
5
|
apt-get update && \
|
|
6
|
-
apt-get install -y ruby2.
|
|
6
|
+
apt-get install -y ruby2.3 ruby2.3-dev libsqlite3-dev libssl-dev pkg-config make cmake
|
|
7
7
|
|
|
8
8
|
RUN gem install oxidized oxidized-web --no-ri --no-rdoc
|
|
9
9
|
|
data/Gemfile.lock
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: .
|
|
3
3
|
specs:
|
|
4
|
-
oxidized (0.
|
|
4
|
+
oxidized (0.17.0)
|
|
5
5
|
asetus (~> 0.1)
|
|
6
|
-
net-ssh (
|
|
6
|
+
net-ssh (~> 3.0.2)
|
|
7
|
+
net-telnet
|
|
7
8
|
rugged (~> 0.21, >= 0.21.4)
|
|
8
9
|
slop (~> 3.5)
|
|
9
10
|
|
|
@@ -14,16 +15,17 @@ GEM
|
|
|
14
15
|
coderay (1.1.0)
|
|
15
16
|
metaclass (0.0.4)
|
|
16
17
|
method_source (0.8.2)
|
|
17
|
-
minitest (5.
|
|
18
|
+
minitest (5.9.0)
|
|
18
19
|
mocha (1.1.0)
|
|
19
20
|
metaclass (~> 0.0.1)
|
|
20
21
|
net-ssh (3.0.2)
|
|
22
|
+
net-telnet (0.1.1)
|
|
21
23
|
pry (0.10.3)
|
|
22
24
|
coderay (~> 1.1.0)
|
|
23
25
|
method_source (~> 0.8.1)
|
|
24
26
|
slop (~> 3.4)
|
|
25
|
-
rake (10.
|
|
26
|
-
rugged (0.
|
|
27
|
+
rake (10.5.0)
|
|
28
|
+
rugged (0.23.3)
|
|
27
29
|
slop (3.6.0)
|
|
28
30
|
|
|
29
31
|
PLATFORMS
|
|
@@ -38,4 +40,4 @@ DEPENDENCIES
|
|
|
38
40
|
rake (~> 10.0)
|
|
39
41
|
|
|
40
42
|
BUNDLED WITH
|
|
41
|
-
1.
|
|
43
|
+
1.11.2
|
data/README.md
CHANGED
|
@@ -27,13 +27,16 @@ Oxidized is a network device configuration backup tool. It's a RANCID replacemen
|
|
|
27
27
|
* [Privileged mode](#privileged-mode)
|
|
28
28
|
* [Disabling SSH exec channels](#disabling-ssh-exec-channels)
|
|
29
29
|
* [Source: CSV](#source-csv)
|
|
30
|
-
* [Source:
|
|
30
|
+
* [Source: SQL](#source-sql)
|
|
31
|
+
* [Source: SQLite](#source-sqlite)
|
|
32
|
+
* [Source: Mysql](#source-mysql)
|
|
31
33
|
* [Source: HTTP](#source-http)
|
|
32
34
|
* [Output: GIT](#output-git)
|
|
33
35
|
* [Output: HTTP](#output-http)
|
|
34
36
|
* [Output: File](#output-file)
|
|
35
37
|
* [Output types](#output-types)
|
|
36
38
|
* [Advanced Configuration](#advanced-configuration)
|
|
39
|
+
* [Advanced Group Configuration](#advanced-group-configuration)
|
|
37
40
|
7. [Ruby API](#ruby-api)
|
|
38
41
|
* [Input](#input)
|
|
39
42
|
* [Output](#output)
|
|
@@ -41,99 +44,103 @@ Oxidized is a network device configuration backup tool. It's a RANCID replacemen
|
|
|
41
44
|
* [Model](#model)
|
|
42
45
|
|
|
43
46
|
# Supported OS types
|
|
47
|
+
* Vendor
|
|
48
|
+
* OS - model_name
|
|
44
49
|
|
|
45
50
|
* A10 Networks
|
|
46
|
-
* ACOS
|
|
51
|
+
* ACOS - acos
|
|
47
52
|
* Alcatel-Lucent
|
|
48
|
-
* AOS
|
|
49
|
-
* AOS7
|
|
50
|
-
* ISAM
|
|
53
|
+
* AOS - aos
|
|
54
|
+
* AOS7 - aos7
|
|
55
|
+
* ISAM - isam
|
|
51
56
|
* Wireless
|
|
57
|
+
* Alvarion
|
|
58
|
+
* BreezeACCESS - alvarion
|
|
52
59
|
* Arista
|
|
53
|
-
* EOS
|
|
60
|
+
* EOS - eos
|
|
54
61
|
* Arris
|
|
55
|
-
* C4CMTS
|
|
62
|
+
* C4CMTS - c4cmts
|
|
56
63
|
* Aruba
|
|
57
|
-
* AOSW
|
|
64
|
+
* AOSW - aosw
|
|
58
65
|
* Brocade
|
|
59
|
-
* FabricOS
|
|
60
|
-
* Ironware
|
|
61
|
-
* NOS (Network Operating System)
|
|
62
|
-
* Vyatta
|
|
63
|
-
* 6910
|
|
66
|
+
* FabricOS - fabricos
|
|
67
|
+
* Ironware - ironware
|
|
68
|
+
* NOS (Network Operating System) - nos
|
|
69
|
+
* Vyatta - vyatta
|
|
70
|
+
* 6910 - br6910
|
|
64
71
|
* Check Point
|
|
65
|
-
* GaiaOS
|
|
72
|
+
* GaiaOS - gaiaos
|
|
66
73
|
* Ciena
|
|
67
|
-
* SOAS
|
|
74
|
+
* SOAS - saos
|
|
68
75
|
* Cisco
|
|
69
|
-
* AireOS
|
|
70
|
-
* ASA
|
|
71
|
-
* CatOS
|
|
72
|
-
* IOS
|
|
73
|
-
* IOSXR
|
|
74
|
-
* NXOS
|
|
75
|
-
* SMB (Nikola series)
|
|
76
|
+
* AireOS - aireos
|
|
77
|
+
* ASA - asa
|
|
78
|
+
* CatOS - catos
|
|
79
|
+
* IOS - ios
|
|
80
|
+
* IOSXR - iosxr
|
|
81
|
+
* NXOS - nxos
|
|
82
|
+
* SMB (Nikola series)
|
|
76
83
|
* Citrix
|
|
77
|
-
* NetScaler (Virtual Applicance)
|
|
84
|
+
* NetScaler (Virtual Applicance) - netscaler
|
|
78
85
|
* Coriant (former Tellabs)
|
|
79
|
-
* TMOS (8800)
|
|
80
|
-
* 8600
|
|
86
|
+
* TMOS (8800) - tmos
|
|
87
|
+
* 8600 -
|
|
81
88
|
* Cumulus
|
|
82
89
|
* Linux
|
|
83
90
|
* DataCom
|
|
84
91
|
* DmSwitch 3000
|
|
85
92
|
* DELL
|
|
86
|
-
* PowerConnect
|
|
87
|
-
* AOSW
|
|
93
|
+
* PowerConnect - powerconnect
|
|
94
|
+
* AOSW - aosw
|
|
88
95
|
* Ericsson/Redback
|
|
89
|
-
* IPOS (former SEOS)
|
|
96
|
+
* IPOS (former SEOS) - ipos
|
|
90
97
|
* Extreme Networks
|
|
91
|
-
* XOS
|
|
98
|
+
* XOS - xos
|
|
92
99
|
* WM
|
|
93
100
|
* F5
|
|
94
101
|
* TMOS
|
|
95
102
|
* Force10
|
|
96
|
-
* DNOS
|
|
97
|
-
* FTOS
|
|
103
|
+
* DNOS - dnos
|
|
104
|
+
* FTOS - ftos
|
|
98
105
|
* FortiGate
|
|
99
|
-
* FortiOS
|
|
106
|
+
* FortiOS - fortios
|
|
100
107
|
* HP
|
|
101
|
-
* Comware (HP A-series, H3C, 3Com)
|
|
102
|
-
* Procurve
|
|
108
|
+
* Comware (HP A-series, H3C, 3Com) - comware
|
|
109
|
+
* Procurve - procurve
|
|
103
110
|
* Huawei
|
|
104
111
|
* VRP
|
|
105
112
|
* Juniper
|
|
106
113
|
* JunOS
|
|
107
114
|
* ScreenOS (Netscreen)
|
|
108
115
|
* Mellanox
|
|
109
|
-
* MLNX-OS
|
|
116
|
+
* MLNX-OS - mlnxos
|
|
110
117
|
* Mikrotik
|
|
111
|
-
* RouterOS
|
|
118
|
+
* RouterOS - routeros
|
|
112
119
|
* Motorola
|
|
113
120
|
* RFS
|
|
114
121
|
* MRV
|
|
115
|
-
* MasterOS
|
|
122
|
+
* MasterOS - masteros
|
|
116
123
|
* Netonix
|
|
117
|
-
* WISP Switch (As Netonix)
|
|
124
|
+
* WISP Switch (As Netonix) - netonix
|
|
118
125
|
* Nokia (formerly TiMetra, Alcatel, Alcatel-Lucent)
|
|
119
|
-
* SR OS (TiMOS)
|
|
126
|
+
* SR OS (TiMOS) - timos
|
|
120
127
|
* Opengear
|
|
121
|
-
* Opengear
|
|
128
|
+
* Opengear - opengear
|
|
122
129
|
* Palo Alto
|
|
123
|
-
* PANOS
|
|
124
|
-
* pfSense
|
|
130
|
+
* PANOS - panos
|
|
131
|
+
* pfSense - pfsense
|
|
125
132
|
* Quanta
|
|
126
|
-
* Quanta / VxWorks 6.6 (1.1.0.8)
|
|
133
|
+
* Quanta / VxWorks 6.6 (1.1.0.8) - quantaos
|
|
127
134
|
* Supermicro
|
|
128
|
-
* Supermicro
|
|
135
|
+
* Supermicro - supermicro
|
|
129
136
|
* Ubiquiti
|
|
130
|
-
* AirOS
|
|
131
|
-
* Edgeos
|
|
132
|
-
* EdgeSwitch
|
|
137
|
+
* AirOS - airos
|
|
138
|
+
* Edgeos - edgeos
|
|
139
|
+
* EdgeSwitch - edgeswitch
|
|
133
140
|
* Watchguard
|
|
134
|
-
* Fireware OS
|
|
141
|
+
* Fireware OS - firewareos
|
|
135
142
|
* Zyxel
|
|
136
|
-
* ZyNOS
|
|
143
|
+
* ZyNOS - zynos
|
|
137
144
|
|
|
138
145
|
|
|
139
146
|
# Installation
|
|
@@ -147,7 +154,7 @@ gem install oxidized-script oxidized-web # if you don't install oxidized-web, ma
|
|
|
147
154
|
```
|
|
148
155
|
|
|
149
156
|
## CentOS, Oracle Linux, Red Hat Linux
|
|
150
|
-
On CentOS 6 / RHEL 6, install Ruby 1.9.3
|
|
157
|
+
On CentOS 6 / RHEL 6, install Ruby greater than 1.9.3 (for Ruby 2.1.2 installation instructions see "Installing Ruby 2.1.2 using RVM"), then install Oxidized dependencies
|
|
151
158
|
```shell
|
|
152
159
|
yum install cmake sqlite-devel openssl-devel libssh2-devel
|
|
153
160
|
```
|
|
@@ -254,46 +261,54 @@ rvm use --default 2.1.2
|
|
|
254
261
|
```
|
|
255
262
|
|
|
256
263
|
# Running with Docker
|
|
257
|
-
|
|
264
|
+
|
|
265
|
+
clone git repo:
|
|
258
266
|
|
|
259
267
|
```
|
|
260
|
-
|
|
261
|
-
```
|
|
262
|
-
2. build container locally:
|
|
268
|
+
git clone https://github.com/ytti/oxidized
|
|
263
269
|
```
|
|
264
|
-
|
|
270
|
+
|
|
271
|
+
build container locally:
|
|
272
|
+
|
|
265
273
|
```
|
|
266
|
-
|
|
274
|
+
docker build -q -t oxidized/oxidized:latest oxidized/
|
|
267
275
|
```
|
|
268
|
-
|
|
276
|
+
|
|
277
|
+
create config directory in main system:
|
|
278
|
+
|
|
269
279
|
```
|
|
270
|
-
|
|
280
|
+
mkdir /etc/oxidized
|
|
271
281
|
```
|
|
272
|
-
|
|
282
|
+
|
|
283
|
+
run container the first time:
|
|
284
|
+
_Note: this step in only needed for creating Oxidized's configuration file and can be skipped if you already have it
|
|
285
|
+
|
|
273
286
|
```
|
|
274
|
-
|
|
287
|
+
docker run --rm -v /etc/oxidized:/root/.config/oxidized -p 8888:8888/tcp -t oxidized/oxidized:latest oxidized
|
|
275
288
|
```
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
289
|
+
|
|
290
|
+
create the `/etc/oxidized/router.db`
|
|
291
|
+
|
|
279
292
|
```
|
|
280
|
-
|
|
293
|
+
vim /etc/oxidized/router.db
|
|
281
294
|
```
|
|
282
|
-
root@bla:~# docker run -v /etc/oxidized:/root/.config/oxidized -p 8888:8888/tcp -t oxidized/oxidized:latest
|
|
283
|
-
oxidized[1]: Oxidized starting, running as pid 1
|
|
284
|
-
oxidized[1]: Loaded 1 nodes
|
|
285
|
-
Puma 2.13.4 starting...
|
|
286
|
-
* Min threads: 0, max threads: 16
|
|
287
|
-
* Environment: development
|
|
288
|
-
* Listening on tcp://0.0.0.0:8888
|
|
289
|
-
^C
|
|
290
295
|
|
|
291
|
-
|
|
296
|
+
run container again:
|
|
297
|
+
|
|
298
|
+
```
|
|
299
|
+
docker run -v /etc/oxidized:/root/.config/oxidized -p 8888:8888/tcp -t oxidized/oxidized:latest
|
|
300
|
+
oxidized[1]: Oxidized starting, running as pid 1
|
|
301
|
+
oxidized[1]: Loaded 1 nodes
|
|
302
|
+
Puma 2.13.4 starting...
|
|
303
|
+
* Min threads: 0, max threads: 16
|
|
304
|
+
* Environment: development
|
|
305
|
+
* Listening on tcp://0.0.0.0:8888
|
|
292
306
|
```
|
|
293
307
|
|
|
294
308
|
If you want to have the config automatically reloaded (e.g. when using a http source that changes)
|
|
309
|
+
|
|
295
310
|
```
|
|
296
|
-
|
|
311
|
+
docker run -v /etc/oxidized:/root/.config/oxidized -p 8888:8888/tcp -e CONFIG_RELOAD_INTERVAL=3600 -t oxidized/oxidized:latest
|
|
297
312
|
```
|
|
298
313
|
|
|
299
314
|
## Cookbook
|
|
@@ -386,6 +401,31 @@ vars_map:
|
|
|
386
401
|
ssh_proxy: 3
|
|
387
402
|
...
|
|
388
403
|
```
|
|
404
|
+
### Source: SQL
|
|
405
|
+
Oxidized uses the `sequel` ruby gem. You can use a variety of databases that aren't explicitly listed. For more information visit https://github.com/jeremyevans/sequel Make sure you have the correct adapter!
|
|
406
|
+
### Source: MYSQL
|
|
407
|
+
|
|
408
|
+
```sudo apt-get install libmysqlclient-dev```
|
|
409
|
+
|
|
410
|
+
The values correspond to your fields in the DB such that ip, model, etc are field names in the DB
|
|
411
|
+
|
|
412
|
+
```
|
|
413
|
+
source:
|
|
414
|
+
default: sql
|
|
415
|
+
sql:
|
|
416
|
+
adapter: mysql2
|
|
417
|
+
database: oxidized
|
|
418
|
+
table: nodes
|
|
419
|
+
username: root
|
|
420
|
+
password: rootpass
|
|
421
|
+
map:
|
|
422
|
+
name: ip
|
|
423
|
+
model: model
|
|
424
|
+
username: username
|
|
425
|
+
password: password
|
|
426
|
+
vars_map:
|
|
427
|
+
enable: enable
|
|
428
|
+
```
|
|
389
429
|
|
|
390
430
|
### Source: SQLite
|
|
391
431
|
|
|
@@ -572,7 +612,7 @@ rest: 10.0.0.1:8000/oxidized
|
|
|
572
612
|
|
|
573
613
|
### Advanced Configuration
|
|
574
614
|
|
|
575
|
-
Below is an advanced example configuration. You will be able to (
|
|
615
|
+
Below is an advanced example configuration. You will be able to (optionally) override options per device. The router.db format used is ```hostname:model:username:password:enable_password```. Hostname and model will be the only required options, all others override the global configuration sections.
|
|
576
616
|
|
|
577
617
|
```
|
|
578
618
|
---
|
|
@@ -617,6 +657,28 @@ source:
|
|
|
617
657
|
model_map:
|
|
618
658
|
cisco: ios
|
|
619
659
|
juniper: junos
|
|
660
|
+
|
|
661
|
+
```
|
|
662
|
+
|
|
663
|
+
### Advanced Group Configuration
|
|
664
|
+
|
|
665
|
+
For group specific credentials
|
|
666
|
+
|
|
667
|
+
```
|
|
668
|
+
groups:
|
|
669
|
+
mikrotik:
|
|
670
|
+
username: admin
|
|
671
|
+
password: blank
|
|
672
|
+
ubiquiti:
|
|
673
|
+
username: ubnt
|
|
674
|
+
password: ubnt
|
|
675
|
+
```
|
|
676
|
+
and add group mapping
|
|
677
|
+
```
|
|
678
|
+
map:
|
|
679
|
+
model: 0
|
|
680
|
+
name: 1
|
|
681
|
+
group: 2
|
|
620
682
|
```
|
|
621
683
|
|
|
622
684
|
# Hooks
|
|
@@ -716,7 +778,7 @@ The following objects exist in Oxidized.
|
|
|
716
778
|
## Input
|
|
717
779
|
* gets config from nodes
|
|
718
780
|
* must implement 'connect', 'get', 'cmd'
|
|
719
|
-
* 'ssh' and '
|
|
781
|
+
* 'ssh', 'telnet, ftp, and tftp' implemented
|
|
720
782
|
|
|
721
783
|
## Output
|
|
722
784
|
* stores config
|
data/Rakefile
CHANGED
|
@@ -19,10 +19,10 @@ task :test do
|
|
|
19
19
|
end
|
|
20
20
|
end
|
|
21
21
|
|
|
22
|
-
desc 'Install gem'
|
|
23
|
-
task :install => :build do
|
|
24
|
-
|
|
25
|
-
end
|
|
22
|
+
## desc 'Install gem'
|
|
23
|
+
## task :install => :build do
|
|
24
|
+
## system "sudo -Es sh -c \'umask 022; gem install gems/#{file}\'"
|
|
25
|
+
## end
|
|
26
26
|
|
|
27
27
|
desc 'Remove gems'
|
|
28
28
|
task :clean do
|
data/extra/rest_client.rb
CHANGED
|
@@ -2,8 +2,30 @@ module Oxidized
|
|
|
2
2
|
class RestClient
|
|
3
3
|
require 'net/http'
|
|
4
4
|
require 'json'
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
require 'uri'
|
|
6
|
+
require 'asetus'
|
|
7
|
+
|
|
8
|
+
class Config
|
|
9
|
+
Root = Root = ENV['OXIDIZED_HOME'] || File.join(ENV['HOME'], '.config', 'oxidized')
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
CFGS = Asetus.new :name=>'oxidized', :load=>false, :key_to_s=>true
|
|
13
|
+
CFGS.default.rest = '127.0.0.1:8888'
|
|
14
|
+
|
|
15
|
+
begin
|
|
16
|
+
CFGS.load
|
|
17
|
+
rescue => error
|
|
18
|
+
raise InvalidConfig, "Error loading config: #{error.message}"
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
restcfg = CFGS.cfg.rest
|
|
22
|
+
unless restcfg.match(/^http:\/\//)
|
|
23
|
+
restcfg.insert(0, 'http://')
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
HOST = URI(restcfg).host
|
|
27
|
+
PORT = URI(restcfg).port
|
|
28
|
+
PATH = URI(restcfg).path
|
|
7
29
|
|
|
8
30
|
class << self
|
|
9
31
|
def next opt={}, host=HOST, port=PORT
|
|
@@ -18,7 +40,7 @@ module Oxidized
|
|
|
18
40
|
|
|
19
41
|
def next opt
|
|
20
42
|
data = JSON.dump opt
|
|
21
|
-
@web.put '/node/next/' + opt[:name].to_s, data
|
|
43
|
+
@web.put PATH + '/node/next/' + opt[:name].to_s, data
|
|
22
44
|
end
|
|
23
45
|
|
|
24
46
|
end
|
data/lib/oxidized/input/ssh.rb
CHANGED
|
@@ -42,7 +42,7 @@ module Oxidized
|
|
|
42
42
|
unless @exec
|
|
43
43
|
shell_open @ssh
|
|
44
44
|
begin
|
|
45
|
-
|
|
45
|
+
login
|
|
46
46
|
rescue Timeout::Error
|
|
47
47
|
raise PromptUndetect, [ @output, 'not matching configured prompt', @node.prompt ].join(' ')
|
|
48
48
|
end
|
|
@@ -102,13 +102,18 @@ module Oxidized
|
|
|
102
102
|
end
|
|
103
103
|
end
|
|
104
104
|
|
|
105
|
-
#
|
|
106
|
-
#
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
105
|
+
# some models have SSH auth or terminal auth based on version of code
|
|
106
|
+
# if SSH is configured for terminal auth, we'll still try to detect prompt
|
|
107
|
+
def login
|
|
108
|
+
if @username
|
|
109
|
+
match = expect username, @node.prompt
|
|
110
|
+
if match == username
|
|
111
|
+
cmd @node.auth[:username], password
|
|
112
|
+
cmd @node.auth[:password]
|
|
113
|
+
end
|
|
114
|
+
else
|
|
115
|
+
expect @node.prompt
|
|
116
|
+
end
|
|
112
117
|
end
|
|
113
118
|
|
|
114
119
|
def exec state=nil
|
|
@@ -123,14 +128,18 @@ module Oxidized
|
|
|
123
128
|
@output
|
|
124
129
|
end
|
|
125
130
|
|
|
126
|
-
def expect
|
|
127
|
-
|
|
131
|
+
def expect *regexps
|
|
132
|
+
regexps = [regexps].flatten
|
|
133
|
+
Oxidized.logger.debug "lib/oxidized/input/ssh.rb: expecting #{regexps.inspect} at #{node.name}"
|
|
128
134
|
Timeout::timeout(Oxidized.config.timeout) do
|
|
129
135
|
@ssh.loop(0.1) do
|
|
130
136
|
sleep 0.1
|
|
131
|
-
|
|
137
|
+
match = regexps.find { |regexp| @output.match regexp }
|
|
138
|
+
return match if match
|
|
139
|
+
true
|
|
132
140
|
end
|
|
133
141
|
end
|
|
134
142
|
end
|
|
143
|
+
|
|
135
144
|
end
|
|
136
145
|
end
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
module Oxidized
|
|
2
|
+
require 'stringio'
|
|
3
|
+
require_relative 'cli'
|
|
4
|
+
|
|
5
|
+
begin
|
|
6
|
+
require 'net/tftp'
|
|
7
|
+
rescue LoadError
|
|
8
|
+
raise OxidizedError, 'net/tftp not found: sudo gem install net-tftp'
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
class TFTP < Input
|
|
12
|
+
|
|
13
|
+
include Input::CLI
|
|
14
|
+
|
|
15
|
+
# TFTP utilizes UDP, there is not a connection. We simply specify an IP and send/receive data.
|
|
16
|
+
def connect node
|
|
17
|
+
@node = node
|
|
18
|
+
|
|
19
|
+
@node.model.cfg['tftp'].each { |cb| instance_exec(&cb) }
|
|
20
|
+
@log = File.open(Oxidized::Config::Log + "/#{@node.ip}-tftp", 'w') if Oxidized.config.input.debug?
|
|
21
|
+
@tftp = Net::TFTP.new @node.ip
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def cmd file
|
|
25
|
+
Oxidized.logger.debug "TFTP: #{file} @ #{@node.name}"
|
|
26
|
+
config = StringIO.new
|
|
27
|
+
@tftp.getbinary file, config
|
|
28
|
+
config.rewind
|
|
29
|
+
config.read
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
private
|
|
33
|
+
|
|
34
|
+
def disconnect
|
|
35
|
+
# TFTP uses UDP, there is no connection to close
|
|
36
|
+
ensure
|
|
37
|
+
@log.close if Oxidized.config.input.debug?
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
end
|
|
41
|
+
end
|
data/lib/oxidized/model/catos.rb
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
class Catos < Oxidized::Model
|
|
2
2
|
|
|
3
|
-
prompt /^[\w.@-]
|
|
3
|
+
prompt /^[\w.@-]+>\s?(\(enable\) )?$/
|
|
4
4
|
comment '# '
|
|
5
5
|
|
|
6
6
|
cmd :all do |cfg|
|
|
@@ -28,8 +28,15 @@ class Catos < Oxidized::Model
|
|
|
28
28
|
password /^Password:/
|
|
29
29
|
end
|
|
30
30
|
|
|
31
|
-
cfg :
|
|
31
|
+
cfg :telnet, :ssh do
|
|
32
32
|
post_login 'set length 0'
|
|
33
|
+
# preferred way to handle additional passwords
|
|
34
|
+
if vars :enable
|
|
35
|
+
post_login do
|
|
36
|
+
send "enable\n"
|
|
37
|
+
cmd vars(:enable)
|
|
38
|
+
end
|
|
39
|
+
end
|
|
33
40
|
pre_logout 'exit'
|
|
34
41
|
end
|
|
35
42
|
|
|
@@ -2,21 +2,12 @@ class PfSense < Oxidized::Model
|
|
|
2
2
|
|
|
3
3
|
# use other use than 'admin' user, 'admin' user cannot get ssh/exec. See issue #535
|
|
4
4
|
|
|
5
|
-
comment '# '
|
|
6
|
-
|
|
7
|
-
#add a comment in the final conf
|
|
8
|
-
def add_comment comment
|
|
9
|
-
"\n###### #{comment} ######\n"
|
|
10
|
-
end
|
|
11
|
-
|
|
12
5
|
cmd :all do |cfg|
|
|
13
6
|
cfg.each_line.to_a[1..-2].join
|
|
14
7
|
end
|
|
15
8
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
cfg = add_comment 'Configuration'
|
|
19
|
-
cfg += cmd 'cat /cf/conf/config.xml'
|
|
9
|
+
cmd 'cat /cf/conf/config.xml' do |cfg|
|
|
10
|
+
cfg.gsub! /\s<revision>\s*<time>\d*<\/time>\s*.*\s*.*\s*<\/revision>/, ''
|
|
20
11
|
end
|
|
21
12
|
|
|
22
13
|
cfg :ssh do
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
class RouterOS < Oxidized::Model
|
|
2
|
-
prompt /\[\w+@\S
|
|
2
|
+
prompt /\[\w+@\S+(\s?\S+)*\]\s?>\s?$/
|
|
3
3
|
comment "# "
|
|
4
4
|
|
|
5
5
|
cmd '/system routerboard print' do |cfg|
|
|
@@ -8,6 +8,7 @@ class RouterOS < Oxidized::Model
|
|
|
8
8
|
|
|
9
9
|
cmd '/export' do |cfg|
|
|
10
10
|
cfg.gsub! /\x1B\[([0-9]{1,3}((;[0-9]{1,3})*)?)?[m|K]/, '' # strip ANSI colours
|
|
11
|
+
cfg.gsub! /\\\r\n\s+/, '' # strip new line
|
|
11
12
|
cfg = cfg.split("\n").select { |line| not line[/^\#\s\w{3}\/\d{2}\/\d{4}.*$/] }
|
|
12
13
|
cfg.join("\n") + "\n"
|
|
13
14
|
end
|
data/lib/oxidized/node.rb
CHANGED
|
@@ -128,24 +128,15 @@ module Oxidized
|
|
|
128
128
|
end
|
|
129
129
|
|
|
130
130
|
def resolve_auth opt
|
|
131
|
-
# Resolve configured username/password
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
elsif ['username', 'password'].all? {|e| Oxidized.config.has_key?(e)}
|
|
137
|
-
[Oxidized.config.username, Oxidized.config.password]
|
|
138
|
-
else
|
|
139
|
-
[nil, nil]
|
|
140
|
-
end
|
|
141
|
-
auth = {}
|
|
142
|
-
auth[:username] = (opt[:username] or cfg_username)
|
|
143
|
-
auth[:password] = (opt[:password] or cfg_password)
|
|
144
|
-
auth
|
|
131
|
+
# Resolve configured username/password
|
|
132
|
+
{
|
|
133
|
+
username: resolve_key(:username, opt),
|
|
134
|
+
password: resolve_key(:password, opt),
|
|
135
|
+
}
|
|
145
136
|
end
|
|
146
137
|
|
|
147
138
|
def resolve_input opt
|
|
148
|
-
inputs =
|
|
139
|
+
inputs = resolve_key :input, opt, Oxidized.config.input.default
|
|
149
140
|
inputs.split(/\s*,\s*/).map do |input|
|
|
150
141
|
if not Oxidized.mgr.input[input]
|
|
151
142
|
Oxidized.mgr.add_input input or raise MethodNotFound, "#{input} not found for node #{ip}"
|
|
@@ -155,7 +146,7 @@ module Oxidized
|
|
|
155
146
|
end
|
|
156
147
|
|
|
157
148
|
def resolve_output opt
|
|
158
|
-
output =
|
|
149
|
+
output = resolve_key :output, opt, Oxidized.config.output.default
|
|
159
150
|
if not Oxidized.mgr.output[output]
|
|
160
151
|
Oxidized.mgr.add_output output or raise MethodNotFound, "#{output} not found for node #{ip}"
|
|
161
152
|
end
|
|
@@ -163,7 +154,7 @@ module Oxidized
|
|
|
163
154
|
end
|
|
164
155
|
|
|
165
156
|
def resolve_model opt
|
|
166
|
-
model =
|
|
157
|
+
model = resolve_key :model, opt
|
|
167
158
|
if not Oxidized.mgr.model[model]
|
|
168
159
|
Oxidized.logger.debug "lib/oxidized/node.rb: Loading model #{model.inspect}"
|
|
169
160
|
Oxidized.mgr.add_model model or raise ModelNotFound, "#{model} not found for node #{ip}"
|
|
@@ -187,6 +178,33 @@ module Oxidized
|
|
|
187
178
|
end
|
|
188
179
|
end
|
|
189
180
|
|
|
181
|
+
def resolve_key key, opt, global=nil
|
|
182
|
+
# resolve key, first get global, then get group then get node config
|
|
183
|
+
key_sym = key.to_sym
|
|
184
|
+
key_str = key.to_s
|
|
185
|
+
value = global
|
|
186
|
+
Oxidized.logger.debug "node.rb: resolving node key '#{key}', with passed global value of '#{value}' and node value '#{opt[key_sym]}'"
|
|
187
|
+
|
|
188
|
+
#global
|
|
189
|
+
if not value and Oxidized.config.has_key?(key_str)
|
|
190
|
+
value = Oxidized.config[key_str]
|
|
191
|
+
Oxidized.logger.debug "node.rb: setting node key '#{key}' to value '#{value}' from global"
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
#group
|
|
195
|
+
if Oxidized.config.groups.has_key?(@group)
|
|
196
|
+
if Oxidized.config.groups[@group].has_key?(key_str)
|
|
197
|
+
value = Oxidized.config.groups[@group][key_str]
|
|
198
|
+
Oxidized.logger.debug "node.rb: setting node key '#{key}' to value '#{value}' from group"
|
|
199
|
+
end
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
#node
|
|
203
|
+
value = opt[key_sym] || value
|
|
204
|
+
Oxidized.logger.debug "node.rb: returning node key '#{key}' with value '#{value}'"
|
|
205
|
+
value
|
|
206
|
+
end
|
|
207
|
+
|
|
190
208
|
def is_git? opt
|
|
191
209
|
(opt[:output] || Oxidized.config.output.default) == 'git'
|
|
192
210
|
end
|
data/lib/oxidized/output/file.rb
CHANGED
|
@@ -17,7 +17,7 @@ class OxidizedFile < Output
|
|
|
17
17
|
end
|
|
18
18
|
|
|
19
19
|
def store node, outputs, opt={}
|
|
20
|
-
file = @cfg.directory
|
|
20
|
+
file = File.expand_path @cfg.directory
|
|
21
21
|
if opt[:group]
|
|
22
22
|
file = File.join File.dirname(file), opt[:group]
|
|
23
23
|
end
|
|
@@ -28,14 +28,16 @@ class OxidizedFile < Output
|
|
|
28
28
|
end
|
|
29
29
|
|
|
30
30
|
def fetch node, group
|
|
31
|
-
cfg_dir = @cfg.directory
|
|
31
|
+
cfg_dir = File.expand_path @cfg.directory
|
|
32
|
+
node_name = node.name
|
|
33
|
+
|
|
32
34
|
if group # group is explicitly defined by user
|
|
33
|
-
IO.readlines File.join(cfg_dir, group,
|
|
35
|
+
IO.readlines File.join(cfg_dir, group, node_name)
|
|
34
36
|
else
|
|
35
|
-
if File.exists? File.join(cfg_dir,
|
|
36
|
-
IO.readlines File.join(cfg_dir,
|
|
37
|
+
if File.exists? File.join(cfg_dir, node_name) # node configuration file is stored on base directory
|
|
38
|
+
IO.readlines File.join(cfg_dir, node_name)
|
|
37
39
|
else
|
|
38
|
-
path = Dir.glob File.join(cfg_dir, '**',
|
|
40
|
+
path = Dir.glob File.join(cfg_dir, '**', node_name) # fetch node in all groups
|
|
39
41
|
return nil if path[0].nil?
|
|
40
42
|
open(path[0], 'r').readlines
|
|
41
43
|
end
|
data/lib/oxidized/source/csv.rb
CHANGED
|
@@ -20,7 +20,7 @@ class CSV < Source
|
|
|
20
20
|
nodes = []
|
|
21
21
|
open(File.expand_path @cfg.file).each_line do |line|
|
|
22
22
|
next if line.match(/^\s*#/)
|
|
23
|
-
data = line.chomp.split
|
|
23
|
+
data = line.chomp.split(@cfg.delimiter, -1)
|
|
24
24
|
next if data.empty?
|
|
25
25
|
# map node parameters
|
|
26
26
|
keys = {}
|
|
@@ -29,9 +29,11 @@ class CSV < Source
|
|
|
29
29
|
end
|
|
30
30
|
keys[:model] = map_model keys[:model] if keys.key? :model
|
|
31
31
|
|
|
32
|
-
# map node specific vars
|
|
32
|
+
# map node specific vars
|
|
33
33
|
vars = {}
|
|
34
|
-
@cfg.vars_map.each
|
|
34
|
+
@cfg.vars_map.each do |key, position|
|
|
35
|
+
vars[key.to_sym] = node_var_interpolate data[position]
|
|
36
|
+
end
|
|
35
37
|
keys[:vars] = vars unless vars.empty?
|
|
36
38
|
|
|
37
39
|
nodes << keys
|
data/lib/oxidized/source/http.rb
CHANGED
|
@@ -43,9 +43,11 @@ class HTTP < Source
|
|
|
43
43
|
end
|
|
44
44
|
keys[:model] = map_model keys[:model] if keys.key? :model
|
|
45
45
|
|
|
46
|
-
# map node specific vars
|
|
46
|
+
# map node specific vars
|
|
47
47
|
vars = {}
|
|
48
|
-
@cfg.vars_map.each
|
|
48
|
+
@cfg.vars_map.each do |key, position|
|
|
49
|
+
vars[key.to_sym] = node_var_interpolate line[position]
|
|
50
|
+
end
|
|
49
51
|
keys[:vars] = vars unless vars.empty?
|
|
50
52
|
|
|
51
53
|
nodes << keys
|
|
@@ -1,11 +1,23 @@
|
|
|
1
1
|
module Oxidized
|
|
2
2
|
class Source
|
|
3
3
|
class NoConfig < OxidizedError; end
|
|
4
|
+
|
|
4
5
|
def initialize
|
|
5
6
|
@map = (Oxidized.config.model_map or {})
|
|
6
7
|
end
|
|
8
|
+
|
|
7
9
|
def map_model model
|
|
8
10
|
@map.has_key?(model) ? @map[model] : model
|
|
9
11
|
end
|
|
12
|
+
|
|
13
|
+
def node_var_interpolate var
|
|
14
|
+
case var
|
|
15
|
+
when "nil" then nil
|
|
16
|
+
when "false" then false
|
|
17
|
+
when "true" then true
|
|
18
|
+
else var
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
10
22
|
end
|
|
11
23
|
end
|
data/lib/oxidized/source/sql.rb
CHANGED
|
@@ -31,7 +31,9 @@ class SQL < Source
|
|
|
31
31
|
|
|
32
32
|
# map node specific vars
|
|
33
33
|
vars = {}
|
|
34
|
-
@cfg.vars_map.each
|
|
34
|
+
@cfg.vars_map.each do |key, sql_column|
|
|
35
|
+
vars[key.to_sym] = node_var_interpolate node[sql_column.to_sym]
|
|
36
|
+
end
|
|
35
37
|
keys[:vars] = vars unless vars.empty?
|
|
36
38
|
|
|
37
39
|
nodes << keys
|
data/lib/oxidized/version.rb
CHANGED
data/oxidized.gemspec
CHANGED
|
@@ -21,7 +21,7 @@ Gem::Specification.new do |s|
|
|
|
21
21
|
s.required_ruby_version = '>= 2.0.0'
|
|
22
22
|
s.add_runtime_dependency 'asetus', '~> 0.1'
|
|
23
23
|
s.add_runtime_dependency 'slop', '~> 3.5'
|
|
24
|
-
s.add_runtime_dependency 'net-ssh', '
|
|
24
|
+
s.add_runtime_dependency 'net-ssh', '~> 3.0.2'
|
|
25
25
|
s.add_runtime_dependency 'rugged', '~> 0.21', '>= 0.21.4'
|
|
26
26
|
|
|
27
27
|
if defined?(RUBY_VERSION) && RUBY_VERSION > '2.3'
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: oxidized
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.17.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Saku Ytti
|
|
@@ -10,7 +10,7 @@ authors:
|
|
|
10
10
|
autorequire:
|
|
11
11
|
bindir: bin
|
|
12
12
|
cert_chain: []
|
|
13
|
-
date: 2016-
|
|
13
|
+
date: 2016-09-28 00:00:00.000000000 Z
|
|
14
14
|
dependencies:
|
|
15
15
|
- !ruby/object:Gem::Dependency
|
|
16
16
|
name: asetus
|
|
@@ -44,22 +44,16 @@ dependencies:
|
|
|
44
44
|
name: net-ssh
|
|
45
45
|
requirement: !ruby/object:Gem::Requirement
|
|
46
46
|
requirements:
|
|
47
|
-
- - "
|
|
48
|
-
- !ruby/object:Gem::Version
|
|
49
|
-
version: 3.0.0
|
|
50
|
-
- - "<"
|
|
47
|
+
- - "~>"
|
|
51
48
|
- !ruby/object:Gem::Version
|
|
52
|
-
version:
|
|
49
|
+
version: 3.0.2
|
|
53
50
|
type: :runtime
|
|
54
51
|
prerelease: false
|
|
55
52
|
version_requirements: !ruby/object:Gem::Requirement
|
|
56
53
|
requirements:
|
|
57
|
-
- - "
|
|
58
|
-
- !ruby/object:Gem::Version
|
|
59
|
-
version: 3.0.0
|
|
60
|
-
- - "<"
|
|
54
|
+
- - "~>"
|
|
61
55
|
- !ruby/object:Gem::Version
|
|
62
|
-
version:
|
|
56
|
+
version: 3.0.2
|
|
63
57
|
- !ruby/object:Gem::Dependency
|
|
64
58
|
name: rugged
|
|
65
59
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -211,12 +205,14 @@ files:
|
|
|
211
205
|
- lib/oxidized/input/input.rb
|
|
212
206
|
- lib/oxidized/input/ssh.rb
|
|
213
207
|
- lib/oxidized/input/telnet.rb
|
|
208
|
+
- lib/oxidized/input/tftp.rb
|
|
214
209
|
- lib/oxidized/job.rb
|
|
215
210
|
- lib/oxidized/jobs.rb
|
|
216
211
|
- lib/oxidized/manager.rb
|
|
217
212
|
- lib/oxidized/model/acos.rb
|
|
218
213
|
- lib/oxidized/model/aireos.rb
|
|
219
214
|
- lib/oxidized/model/airos.rb
|
|
215
|
+
- lib/oxidized/model/alvarion
|
|
220
216
|
- lib/oxidized/model/aos.rb
|
|
221
217
|
- lib/oxidized/model/aos7.rb
|
|
222
218
|
- lib/oxidized/model/aosw.rb
|