net-ops 0.0.5.pre → 0.0.6.pre

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 6ddd5aa75208c9e4c9cca7e3b132134453117747
4
- data.tar.gz: 7f7cb228b4234a18e901c3d0bf77d19a0c637c90
3
+ metadata.gz: 34f9d13e55ceb5c908ac02977a65af34cf800351
4
+ data.tar.gz: 590c49b48e2f3332638b6fbc15957db6986345c8
5
5
  SHA512:
6
- metadata.gz: 024cbbd43efc3e9381db9fa65446fee4f08626cb424cebeefefe04ec039f9679f23cd85d9d6fcbde32f95cc956af0f0212b5f1a089164ecb107c47f106ff8ad0
7
- data.tar.gz: b74d3628a96ae7753f37268c5031be99251ee92321b3985255bdb2a209274211fd189e9ec4a0b9cd1088cd73aab24c52e105829af685321de3434d1ac5afcfb8
6
+ metadata.gz: c0a759af3c60da04e28c79483b2f373b53747b535c12165202a65fa08291cef52a6020f8f492fdbd57ee0ae52557ac92e4eb8df348867a9fbdd6da3532c8b687
7
+ data.tar.gz: 3aed13236fa58b023460b17c326cf4314c8d9ddc868a39349b38137231734de471821c4b02d756fb21b2ed9c0841c95d149cec01ff119d90573e0673272b8f17
data/.gitignore ADDED
@@ -0,0 +1,22 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ coverage
6
+ InstalledFiles
7
+ lib/bundler/man
8
+ pkg
9
+ rdoc
10
+ spec/reports
11
+ test/tmp
12
+ test/version_tmp
13
+ tmp
14
+ Gemfile.lock
15
+
16
+ # YARD artifacts
17
+ .yardoc
18
+ _yardoc
19
+ doc/
20
+
21
+ credentials.yml
22
+ *~
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in net-ops.gemspec
4
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2013 Maxime Mouchet
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
6
+ this software and associated documentation files (the "Software"), to deal in
7
+ the Software without restriction, including without limitation the rights to
8
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9
+ the Software, and to permit persons to whom the Software is furnished to do so,
10
+ subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17
+ FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18
+ COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,334 @@
1
+ # Net::Ops
2
+
3
+ ## Ruby framework for interacting with network devices
4
+
5
+ Computers are made to simplify our lives, not make them more complicated. They don't mind doing 1000x the same thing but too often people do repetitive tasks at hand because they don't know how to write scripts.
6
+ I developed this little Ruby module to simplify daily operations on network devices like switches, routers, and access-points.
7
+
8
+ ### Prerequisites
9
+
10
+ I made it to be as simple as possible but, if you want to understand how it works or extend it, you will need some Ruby knowledge.
11
+ [The Little Book of Ruby](http://www.sapphiresteel.com/The-Little-Book-Of-Ruby) is a good introduction altough convention are not always clear.
12
+ [Design Patterns](http://www.amazon.fr/Design-Patterns-Elements-Reusable-Object-Oriented/dp/0201633612) and [Design Patterns in Ruby](http://www.pearsonhighered.com/educator/product/Design-Patterns-in-Ruby/9780321490452.page)
13
+ are must read.
14
+ [Stack Overflow](http://stackoverflow.com/) is a good place in case of problem.
15
+
16
+ ### Compatibility
17
+
18
+ Tested with Cisco IOS and IOS XE devices. Should work partially with NX-OS.
19
+ Not compatible with IOS XR and non-Cisco devices but it would be possible to add an abstraction layer in ops.rb to support other brands.
20
+
21
+ I implemented only two [transports](#transports), Telnet and SSH. If you want to use another protocol (a serial link for example) you will have to implement it.
22
+
23
+
24
+ ## Installation
25
+
26
+ First, you need a Ruby interpreter. [MRI](http://en.wikipedia.org/wiki/Ruby_MRI), the reference implementation, is a good choice. You can download it on [ruby-lang.org](http://www.ruby-lang.org/en/downloads/).
27
+ Note that MRI is already included in Mac OS X and most of the Linux distributions.
28
+ On Ubuntu you can install it with `apt-get install ruby1.9.3`.
29
+ There is other Ruby implementation like [JRuby](http://jruby.org/) or [MagLev](http://maglev.github.io/) but I have not tested my code with them.
30
+
31
+ Then you should intall net-ops. You can get the latest version from RubyGems:
32
+ ```bash
33
+ gem install 'net-ops'
34
+ ```
35
+
36
+ Or build it from the source:
37
+ ```bash
38
+ gem build net-ops.gemspec
39
+ gem install ./net-ops-x.y.z.gem
40
+ ```
41
+
42
+ ## Getting started
43
+
44
+ You need to require net/ops in all your scripts and [tasks](#tasks) (we will talk about this later):
45
+
46
+ ```ruby
47
+ require 'net/ops'
48
+ ```
49
+
50
+ To run a script you can double-click on it (on Windows) or issue `ruby my_script.rb` in a terminal.
51
+
52
+ ### Storing credentials
53
+
54
+ Writing directly your username and password directly in the script is a bad idea.
55
+ If you want to keep things simple you can store them in a [YAML](http://en.wikipedia.org/wiki/YAML) file with the following structure:
56
+ ```yml
57
+ # credentials.yml
58
+ username: user1
59
+ password: r5Xqx8
60
+ ```
61
+ Then, to use them in your script:
62
+
63
+ ```ruby
64
+ credentials = YAML.load_file('credentials.yml')
65
+
66
+ credentials.fetch('username') #=> 'user1'
67
+ credentials.fetch('password') #=> 'r5Xqx8'
68
+ ```
69
+
70
+ *Note 1 : If you don't need a username to connect to your device you can either let it empty or specify any value. The field will be ignored.*
71
+ *Note 2 : Currently the login and the enable password used are the same ([issue #4](https://github.com/maxmouchet/net-ops/issues/4))*
72
+
73
+ ### Connecting to a device
74
+
75
+ Connecting to a device is a two-step process: create a session, and open it.
76
+ Nothing is sent on the transport until you open the session.
77
+
78
+ #### Create the session
79
+
80
+ To create a Session you just need to specify the hostname (or the IP address):
81
+
82
+ ```ruby
83
+ @session = Net::Ops::Session.new('router1.local')
84
+ ```
85
+
86
+ ##### Options
87
+
88
+ You can also customize the timeout (`Integer`) and the prompt (`Regexp`) if you want:
89
+
90
+ ```ruby
91
+ host = 'router1.local'
92
+ options = { timeout: 10, prompt: /.+(#|>)/ }
93
+
94
+ @session = Net::Ops::Session.new(host, options)
95
+ ```
96
+
97
+ ##### Logging
98
+
99
+ By default `Session` logs everything from `Level::DEBUG` to `STDOUT`. You can specify a custom logger to the constructor.
100
+ For example to log everything from `Level::WARN` to a file:
101
+ ```ruby
102
+ logger = Logger.new('logfile.log')
103
+ logger.level = Logger::WARN
104
+
105
+ @session = Net::Ops::Session.new(host, options, logger)
106
+ ```
107
+
108
+ #### Open the session
109
+
110
+ Given you loaded your credentials from a YAML file you can open the session like this:
111
+
112
+ ```ruby
113
+ @session.open({ username: credentials.fetch('username'),
114
+ password: credentials.fetch('password') })
115
+ ```
116
+
117
+ Note that this doesn't handle `Net::Ops::TransportUnavailable` which is raised when no transport can be used to open the session.
118
+ To show the error and prevent your script from stopping:
119
+
120
+ ```ruby
121
+ begin @session.open({ username: '', password: '' })
122
+ rescue Net::Ops::TransportUnavailable => e
123
+ puts "There is an error: #{e.message}"
124
+ end
125
+ ```
126
+
127
+ #### Close the session
128
+
129
+ It is generally not needed to close the session since the Ruby garbage collector will do it automatically.
130
+ However if you need to, you can call `close`:
131
+ ```ruby
132
+ @session.close
133
+ ```
134
+
135
+ ### Sending commands
136
+
137
+ Once the session is opened you can send commands to the device. Net::Ops offer three abstraction levels that are described below.
138
+
139
+ #### Raw commands
140
+
141
+ The basic way to send a command and get the output is the `run(command)` method.
142
+ It send command (`String`) followed by a carriage return to the device, wait for the prompt, and return what happened between.
143
+ For example, to get `show int status` output:
144
+
145
+ ```ruby
146
+ puts @session.run('show int status')
147
+ ```
148
+
149
+ `run(command)` is pretty low-level but sometimes you will want to play directly with the transport.
150
+ For example when the command ask for confirmation and doesn't return the prompt (like `reload`). In this case you can do something like this:
151
+ ```ruby
152
+ transport = @session.transport
153
+ transport.cmd('String' => 'reload', 'Match' => /.+confirm.+/)
154
+ transport.cmd('yes')
155
+ ```
156
+
157
+ To get the output with `transport.cmd` you need to pass a block:
158
+
159
+ ```ruby
160
+ transport = @session.transport
161
+ transport.cmd('show version') { |c| puts c }
162
+ ```
163
+
164
+
165
+ #### Basic commands
166
+
167
+ To make your script easier to read, Net::Ops provides methods which are basically alias to Cisco commands.
168
+ These are `get(item)`, `set(item, value)`, `enable(item)`, and `disable(item)`:
169
+ ```ruby
170
+ @session.get 'interfaces status'
171
+ # send 'show interfaces status'
172
+
173
+ @session.set 'terminal length', 0
174
+ # send 'terminal length 0'
175
+
176
+ @session.enable 'ip http secure-server'
177
+ # send 'ip http secure-server'
178
+
179
+ @session.disable 'spanning-tree bpduguard'
180
+ # send 'no spanning-tree bpduguard'
181
+ ```
182
+
183
+ These methods allow you to write script that are easily readable but you can do much more by combining them with the [DSL](http://en.wikipedia.org/wiki/Domain-specific_language) that Net::Ops provides.
184
+
185
+ #### Domain-specific language
186
+
187
+ Currently the DSL is made of five methods:
188
+ * `privileged(&block)`
189
+ * `configuration(options = nil, &block)`
190
+ * `interface(interface, &block)`
191
+ * `interfaces(interfaces, &block)`
192
+ * `lines(lines, &block)`
193
+
194
+ They allow you to run commands in the specified context. Note that don't have to prefix methods with `@session` since the block is evalued inside the session.
195
+
196
+ Here's an example of how to use it:
197
+ ```ruby
198
+ # Here we pass a block to be executed in the privileged mode.
199
+ @session.privileged do
200
+
201
+ # Let's get interfaces status.
202
+ sw_interfaces = get 'interfaces status'
203
+
204
+ # Show disabled interfaces
205
+ nc_interfaces = sw_interfaces.select { |int| int['status'] == 'disabled' }
206
+ puts nc_interfaces
207
+
208
+ end
209
+
210
+ # Do some stuff in configuration mode.
211
+ @session.configuration do
212
+
213
+ # Add description to Gi1/0/2.
214
+ # Note the singular/plural in interface(s).
215
+ # interface accept only String as an argument.
216
+ # interfaces accept Array, Regexp, and String.
217
+ interface('Gi1/0/2') do
218
+ set 'description', 'I am Gi1/0/2'
219
+ end
220
+
221
+ # Disable bpduguard on all Gig interfaces.
222
+ interfaces(/Gi1\/0/) do
223
+ disable 'spanning-tree bpduguard'
224
+ end
225
+
226
+ end
227
+
228
+ # Copy to startup-config
229
+ @session.write!
230
+
231
+ # Do something else in configuration mode
232
+ # but automatically write this time.
233
+ @session.configuration(:enforce_save) do
234
+ disable 'ip http secure-server'
235
+ end
236
+ ```
237
+
238
+ #### Other commands
239
+
240
+ * `write!`
241
+ * `zeroize(item)`
242
+ * `generate(item, options)`
243
+
244
+ Example :
245
+
246
+ ```ruby
247
+ # Delete the crypto key
248
+ @session.zeroize 'crypto key'
249
+
250
+ # Regenerate it
251
+ @session.generate 'crypto key', 'rsa general-keys modulus 2048'
252
+
253
+ # Save running-config
254
+ @session.write!
255
+ ```
256
+
257
+ ## Tasks
258
+ Net::Ops allow to define tasks that perform a specific action and run it on several devices in parallel while handling errors and providing easy logging.
259
+
260
+ ### Definition
261
+ To define a task you should create a new class that inherit from `Task` and define `initialize` and `work` methods:
262
+
263
+ ```ruby
264
+ # my_task.rb
265
+ class MyTask < Net::Ops::Task
266
+
267
+ def initialize(id)
268
+ # Setup your stuff.
269
+ super(id)
270
+ end
271
+
272
+ def work
273
+ # Place your logic here.
274
+ end
275
+
276
+ end
277
+ ```
278
+
279
+ `id` is an identifier that should be unique for each instance of your task. You can use whatever you want, for example the hostname of the device you are currently working on.
280
+
281
+ ### Execution
282
+ To run a task you can basically instance it and call work:
283
+
284
+ ```ruby
285
+ t = MyTask.new('task1')
286
+ t.work
287
+ ```
288
+
289
+ However you may want to run several tasks in parallel to speed up things. You can do that thanks to [thread/pool](https://github.com/meh/ruby-thread):
290
+
291
+ ```ruby
292
+ hosts = %w( host1 host2 host3 )
293
+ max_conn = 2
294
+
295
+ pool = Thread.pool(max_conn)
296
+
297
+ hosts.each do |hosts|
298
+ pool.process { MyTask.new(host).work }
299
+ end
300
+
301
+ pool.shutdown
302
+ ```
303
+
304
+ ## Transports
305
+
306
+ ### Built-in
307
+
308
+ ### Custom
309
+ ```ruby
310
+ class MyCustomTransport
311
+
312
+ def self.open(host, options, credentials)
313
+ session = # Do what you need to get a session to the host.
314
+ return session
315
+ end
316
+
317
+ end
318
+ ```
319
+
320
+ ## Documentation
321
+ You can get the documentation via gem with `gem server`.
322
+ Or generate it manually with `rake doc`.
323
+
324
+ ## Todo - Ideas
325
+
326
+ See [issues](https://github.com/maxmouchet/net-ops/issues?state=open).
327
+
328
+ ## Contributing
329
+
330
+ 1. Fork it
331
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
332
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
333
+ 4. Push to the branch (`git push origin my-new-feature`)
334
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require 'bundler/gem_tasks'
@@ -0,0 +1,94 @@
1
+ # Sample script that show basic usage of Net::Ops.
2
+ # For more information refer to the documentation.
3
+ # To generate it run `yardoc lib/net/ops/session.rb`.
4
+
5
+ # Add lib/ to the PATH.
6
+ $:.unshift File.join(File.dirname(__FILE__), *%w[lib])
7
+
8
+ require 'rubygems'
9
+ require 'net/ops'
10
+ require 'yaml'
11
+
12
+ # Load credentials from credentials.yml.
13
+ #
14
+ # File format is :
15
+ # username: myusername
16
+ # password: mypassword
17
+ credentials = YAML.load_file('credentials.yml')
18
+
19
+ # Define the timeout and the prompt (optional).
20
+ # Net::Ops::Session.new default to
21
+ # { timeout: 10, prompt: /.+(#|>)/ }
22
+ options = { timeout: 10, prompt: /.+(#|>)/ }
23
+
24
+ # Create a logger (optional).
25
+ # Net::Ops::Session.setup_logger default to
26
+ # logger = Logger.new(STDOUT)
27
+ # logger.level = Logger::DEBUG
28
+ logger = Logger.new(STDOUT)
29
+ logger.level = Logger::DEBUG
30
+
31
+ # Create a session to sa-qcmtlv-11-09 (1).
32
+ # This is the exhaustive form with all optionals params.
33
+ session = Net::Ops::Session.new('sa-qcmtlv-11-09', options, logger)
34
+
35
+ # OR
36
+
37
+ # Create a session to sa-qcmtlv-11-09 (2).
38
+ # This is the short form without the optional params.
39
+ # See the documentation/code for default values.
40
+ session = Net::Ops::Session.new('sa-qcmtlv-11-09')
41
+
42
+ # Open the session using the specified credentials.
43
+ # This form provides the full hash in case
44
+ # key names are not :username and :password.
45
+ # Or if you want to specify credentials directly.
46
+ session.open({ username: credentials.fetch('username'),
47
+ password: credentials.fetch('password') })
48
+
49
+ # Set terminal length to 0 otherwise too long outputs will cause
50
+ # Net::Telnet to timeout while waiting for the prompt.
51
+ session.privileged { set 'terminal length', 0 }
52
+
53
+ # Here we pass a block to be executed in the privileged mode.
54
+ session.privileged do
55
+
56
+ # Let's get interfaces status.
57
+ sw_interfaces = get 'interfaces status'
58
+
59
+ # Show disabled interfaces
60
+ @nc_interfaces = sw_interfaces.select { |int| int['status'] == 'disabled' }
61
+ puts @nc_interfaces
62
+
63
+ end
64
+
65
+ # Do some stuff in configuration mode.
66
+ session.configuration do
67
+
68
+ # Add description to Gi1/0/2.
69
+ # Note the singular/plural in interface(s).
70
+ # interface accept only String as an argument.
71
+ # interfaces accept Array, Regexp, and String.
72
+ interface('Gi1/0/2') do
73
+ set 'description', 'I am Gi1/0/2'
74
+ end
75
+
76
+ # Disable bpduguard on all Gig interfaces.
77
+ interfaces(/Gi1\/0/) do
78
+ disable 'spanning-tree bpduguard'
79
+ end
80
+
81
+ end
82
+
83
+ # Copy to startup-config
84
+ session.write!
85
+
86
+ # Do something else in configuration mode
87
+ # but automatically write this time.
88
+ session.configuration(:enforce_save) do
89
+ disable 'ip http secure-server'
90
+ end
91
+
92
+ # Close the session.
93
+ # Optionnal since Ruby garbage collector should do that for us.
94
+ session.close