net-ops 0.0.5.pre → 0.0.6.pre
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/.gitignore +22 -0
- data/Gemfile +4 -0
- data/LICENSE +20 -0
- data/README.md +334 -0
- data/Rakefile +1 -0
- data/examples/basic_script.rb +94 -0
- data/examples/commands.txt +6 -0
- data/examples/exec_file.rb +21 -0
- data/examples/hosts.txt +2 -0
- data/lib/net/ops.rb +10 -373
- data/lib/net/ops/parser.rb +39 -0
- data/lib/net/ops/session.rb +308 -0
- data/lib/net/ops/task.rb +32 -0
- data/lib/net/ops/transport/ssh.rb +35 -0
- data/lib/net/ops/transport/telnet.rb +49 -0
- data/lib/net/ops/version.rb +5 -0
- data/net-ops.gemspec +26 -0
- data/regexs.yml +12 -0
- data/tasks/downcase_hostname_task.rb +144 -0
- data/tasks/test.rb +21 -0
- metadata +50 -5
- data/lib/net/transport/ssh.rb +0 -39
- data/lib/net/transport/telnet.rb +0 -53
data/regexs.yml
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
cisco:
|
2
|
+
interfaces:
|
3
|
+
status:
|
4
|
+
regex: >
|
5
|
+
(?<short_type>Fa|Gi|Te)
|
6
|
+
(?<port_number>\d+\/\d+(\/\d+)?)\s+
|
7
|
+
(?<description>.+)?\s+
|
8
|
+
(?<status>connected|notconnect|disabled|err-disabled)\s+
|
9
|
+
(?<vlan>\w+|\d+)\s+
|
10
|
+
(?<duplex>auto|(a-)?full)\s+
|
11
|
+
(?<speed>auto|a-1000|10G)\s+
|
12
|
+
(?<type>.+)
|
@@ -0,0 +1,144 @@
|
|
1
|
+
# Task for converting hostname to lowercase.
|
2
|
+
# Handle devices with SSH by regenerating crypto key.
|
3
|
+
|
4
|
+
require '../lib/net/ops'
|
5
|
+
|
6
|
+
class DowncaseHostnameTask < Net::Ops::Task
|
7
|
+
|
8
|
+
def initialize(host, options, credentials)
|
9
|
+
@host = host
|
10
|
+
@options = options
|
11
|
+
@credentials = credentials
|
12
|
+
|
13
|
+
@session = Session.new(host, options)
|
14
|
+
|
15
|
+
super(host)
|
16
|
+
end
|
17
|
+
|
18
|
+
# This is where all the logic is.
|
19
|
+
def work
|
20
|
+
|
21
|
+
# First we need to open the session.
|
22
|
+
# I create a helper because we will have to
|
23
|
+
# (dis)connect several times during this task.
|
24
|
+
connect
|
25
|
+
|
26
|
+
# Set terminal length to 0 otherwise too long outputs will cause
|
27
|
+
# Net::Telnet to timeout while waiting for the prompt.
|
28
|
+
@session.privileged { set 'terminal length', 0 }
|
29
|
+
|
30
|
+
# Check ip http secure-server
|
31
|
+
https = /^ip http secure-server/.match(@session.get('run | i ip http'))
|
32
|
+
|
33
|
+
# Get hostname from show version.
|
34
|
+
match = /(?<hostname>.+)\s+uptime.+/.match(@session.get('version'))
|
35
|
+
|
36
|
+
# Check if we found the hostname
|
37
|
+
# and convert it if needed.
|
38
|
+
# `match['hostname'].downcase!` return nil
|
39
|
+
# if the hostname is already in lowercase.
|
40
|
+
if !https && match && match['hostname'].downcase!
|
41
|
+
|
42
|
+
# If we are connected using SSH we enable Telnet
|
43
|
+
# in case bad crypto key prevent us from logging.
|
44
|
+
enable_telnet if ssh?
|
45
|
+
|
46
|
+
# Convert the hostname
|
47
|
+
info "Converting #{ match['hostname'] } => #{ match['hostname'].downcase }"
|
48
|
+
@session.configuration(:enforce_save) { set 'hostname', match['hostname'].downcase }
|
49
|
+
|
50
|
+
# If SSH is enabled regenerate crypto key
|
51
|
+
# and verify SSH is still working.
|
52
|
+
if ssh?
|
53
|
+
|
54
|
+
# Delete the existing crypto key
|
55
|
+
# then regenerate it.
|
56
|
+
regenerate_crypto
|
57
|
+
|
58
|
+
# Close the session and reopen it
|
59
|
+
# to see if we are still able to
|
60
|
+
# connect via SSH.
|
61
|
+
info 'Verifying SSH is still working'
|
62
|
+
reconnect
|
63
|
+
|
64
|
+
# If SSH is still working we can disable Telnet.
|
65
|
+
if ssh?
|
66
|
+
info 'Hooray SSH is still working !'
|
67
|
+
disable_telnet
|
68
|
+
else warn 'SSH is not working :('
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|
72
|
+
|
73
|
+
elsif match && !match['hostname'].downcase! then info 'Nothing to do'
|
74
|
+
else error 'Unable to find hostname'; end
|
75
|
+
|
76
|
+
@session.close
|
77
|
+
end
|
78
|
+
|
79
|
+
# Below are the helpers methods.
|
80
|
+
# I wrote them to be DRY and reduce code.
|
81
|
+
|
82
|
+
# Open the session and show the transport used.
|
83
|
+
def connect
|
84
|
+
info "Connecting to #{ @host }"
|
85
|
+
|
86
|
+
begin @session.open(@credentials)
|
87
|
+
rescue Exception => e
|
88
|
+
error e.message
|
89
|
+
end
|
90
|
+
|
91
|
+
info "Transport is #{ @session.transport.class }"
|
92
|
+
end
|
93
|
+
|
94
|
+
# Alias for session.close
|
95
|
+
def disconnect
|
96
|
+
@session.close
|
97
|
+
end
|
98
|
+
|
99
|
+
# Disconnect, then reconnect.
|
100
|
+
def reconnect
|
101
|
+
disconnect; connect
|
102
|
+
end
|
103
|
+
|
104
|
+
# True if the transport it SSH.
|
105
|
+
def ssh?
|
106
|
+
@session.transport.class.to_s.include?('SSH')
|
107
|
+
end
|
108
|
+
|
109
|
+
# Enable Telnet and SSH on all VTY lines.
|
110
|
+
def enable_telnet
|
111
|
+
info 'Enabling Telnet'
|
112
|
+
|
113
|
+
@session.configuration(:enforce_save) do
|
114
|
+
lines('vty 0 4') { set 'transport input', 'ssh telnet' }
|
115
|
+
# lines('vty 5 15') { set 'transport input', 'ssh telnet' }
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
# Set SSH only on all VTY lines.
|
120
|
+
def disable_telnet
|
121
|
+
info 'Disabling Telnet'
|
122
|
+
|
123
|
+
@session.configuration(:enforce_save) do
|
124
|
+
lines('vty 0 4') { set 'transport input', 'ssh' }
|
125
|
+
# lines('vty 5 15') { set 'transport input', 'ssh' }
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
# Delete the crypto key then regenerate it.
|
130
|
+
def regenerate_crypto
|
131
|
+
info 'Regenerate crypto key'
|
132
|
+
|
133
|
+
@session.configuration(:enforce_save) do
|
134
|
+
zeroize 'crypto key'
|
135
|
+
begin
|
136
|
+
generate 'crypto key', 'rsa general-keys modulus 2048'
|
137
|
+
rescue Exception => e
|
138
|
+
generate 'crypto key', 'rsa modulus 2048'
|
139
|
+
end
|
140
|
+
set 'ip ssh version', 2
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
end
|
data/tasks/test.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
require './downcase_hostname_task'
|
2
|
+
|
3
|
+
hosts = %w( 192.168.0.104 )
|
4
|
+
|
5
|
+
credentials = YAML.load_file('credentials.yml')
|
6
|
+
|
7
|
+
|
8
|
+
options = { timeout: 30, prompt: /.+(#|>)/ }
|
9
|
+
credentials = { username: credentials.fetch('username'),
|
10
|
+
password: credentials.fetch('username') }
|
11
|
+
|
12
|
+
pool = Thread.pool(10)
|
13
|
+
|
14
|
+
hosts.each do |host|
|
15
|
+
# pool.process do
|
16
|
+
t = DowncaseHostnameTask.new(host, options, credentials)
|
17
|
+
t.work
|
18
|
+
# end
|
19
|
+
end
|
20
|
+
|
21
|
+
pool.shutdown
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: net-ops
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.6.pre
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Maxime Mouchet
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2013-07-
|
11
|
+
date: 2013-07-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: thread
|
@@ -38,16 +38,61 @@ dependencies:
|
|
38
38
|
- - ~>
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: 0.0.2
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: bundler
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ~>
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '1.3'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ~>
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '1.3'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rake
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - '>='
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
41
69
|
description: Framework to automate daily operations on network devices.
|
42
70
|
email:
|
43
|
-
- max@
|
71
|
+
- mouchet.max@gmail.com
|
44
72
|
executables: []
|
45
73
|
extensions: []
|
46
74
|
extra_rdoc_files: []
|
47
75
|
files:
|
76
|
+
- .gitignore
|
77
|
+
- Gemfile
|
78
|
+
- LICENSE
|
79
|
+
- README.md
|
80
|
+
- Rakefile
|
81
|
+
- examples/basic_script.rb
|
82
|
+
- examples/commands.txt
|
83
|
+
- examples/exec_file.rb
|
84
|
+
- examples/hosts.txt
|
48
85
|
- lib/net/ops.rb
|
49
|
-
- lib/net/
|
50
|
-
- lib/net/
|
86
|
+
- lib/net/ops/parser.rb
|
87
|
+
- lib/net/ops/session.rb
|
88
|
+
- lib/net/ops/task.rb
|
89
|
+
- lib/net/ops/transport/ssh.rb
|
90
|
+
- lib/net/ops/transport/telnet.rb
|
91
|
+
- lib/net/ops/version.rb
|
92
|
+
- net-ops.gemspec
|
93
|
+
- regexs.yml
|
94
|
+
- tasks/downcase_hostname_task.rb
|
95
|
+
- tasks/test.rb
|
51
96
|
homepage: http://github.com/maxmouchet/qscripts
|
52
97
|
licenses:
|
53
98
|
- MIT
|
data/lib/net/transport/ssh.rb
DELETED
@@ -1,39 +0,0 @@
|
|
1
|
-
require 'net/ssh/telnet'
|
2
|
-
|
3
|
-
module Net
|
4
|
-
module Ops
|
5
|
-
module Transport
|
6
|
-
|
7
|
-
#
|
8
|
-
class SSH
|
9
|
-
|
10
|
-
# Open an SSH session to the specified host using net/ssh/telnet.
|
11
|
-
#
|
12
|
-
# @param host [String] the destination host.
|
13
|
-
# @param options [Hash]
|
14
|
-
# @param credentials [Hash] credentials to use to connect.
|
15
|
-
def self.open(host, options, credentials)
|
16
|
-
session = nil
|
17
|
-
|
18
|
-
ssh = Net::SSH.start(host, credentials[:username], :password => credentials[:password])
|
19
|
-
session = Net::SSH::Telnet.new('Session' => ssh,
|
20
|
-
'Timeout' => options[:timeout],
|
21
|
-
'Prompt' => options[:prompt])
|
22
|
-
|
23
|
-
rescue Errno::ECONNREFUSED => e
|
24
|
-
session = nil
|
25
|
-
|
26
|
-
rescue Net::SSH::AuthenticationFailed => e
|
27
|
-
session = nil
|
28
|
-
|
29
|
-
rescue Exception => e
|
30
|
-
session = nil
|
31
|
-
|
32
|
-
return session
|
33
|
-
end
|
34
|
-
|
35
|
-
end
|
36
|
-
|
37
|
-
end
|
38
|
-
end
|
39
|
-
end
|
data/lib/net/transport/telnet.rb
DELETED
@@ -1,53 +0,0 @@
|
|
1
|
-
require 'net/telnet'
|
2
|
-
|
3
|
-
module Net
|
4
|
-
module Ops
|
5
|
-
module Transport
|
6
|
-
|
7
|
-
#
|
8
|
-
class Telnet
|
9
|
-
|
10
|
-
# Open a Telnet session to the specified host using net/ssh.
|
11
|
-
#
|
12
|
-
# @param host [String] the destination host.
|
13
|
-
# @param options [Hash]
|
14
|
-
# @param credentials [Hash] credentials to use to connect.
|
15
|
-
def self.open(host, options, credentials)
|
16
|
-
session = nil
|
17
|
-
|
18
|
-
session = Net::Telnet.new('Host' => host,
|
19
|
-
'Timeout' => options[:timeout],
|
20
|
-
'Prompt' => options[:prompt])
|
21
|
-
|
22
|
-
output = ''
|
23
|
-
session.cmd('String' => '', 'Match' => /.+/) { |c| output += c }
|
24
|
-
|
25
|
-
if /[Uu]sername:/.match(output) then
|
26
|
-
session.cmd('String' => credentials[:username],
|
27
|
-
'Match' => /.+/)
|
28
|
-
session.cmd(credentials[:password])
|
29
|
-
end
|
30
|
-
|
31
|
-
if /[Pp]assword:/.match(output) then
|
32
|
-
session.cmd(credentials[:password])
|
33
|
-
end
|
34
|
-
|
35
|
-
return session
|
36
|
-
|
37
|
-
rescue Errno::ECONNREFUSED => e
|
38
|
-
session = nil
|
39
|
-
|
40
|
-
rescue Net::OpenTimeout => e
|
41
|
-
session = nil
|
42
|
-
|
43
|
-
rescue Exception => e
|
44
|
-
session = nil
|
45
|
-
|
46
|
-
return session
|
47
|
-
end
|
48
|
-
|
49
|
-
end
|
50
|
-
|
51
|
-
end
|
52
|
-
end
|
53
|
-
end
|