netdot-restclient 1.4 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -50,6 +50,8 @@ The Netdot user manual at:
50
50
 
51
51
  http://netdot.uoregon.edu
52
52
 
53
+ See the sample/sample.rb for sample usage of the Host and Ipblock classes.
54
+
53
55
  ## Contributing
54
56
 
55
57
  1. Fork it ( https://github.com/cvicente/netdot-restclient/fork )
data/Rakefile CHANGED
@@ -1,2 +1,8 @@
1
- require "bundler/gem_tasks"
1
+ require 'bundler/gem_tasks'
2
+ require 'yard'
2
3
 
4
+ YARD::Rake::YardocTask.new do |_t|
5
+ # t.files = ['lib/**/*.rb', OTHER_PATHS] # optional
6
+ # t.options = ['--any', '--extra', '--opts'] # optional
7
+ # t.stats_options = ['--list-undoc'] # optional
8
+ end
data/lib/netdot.rb CHANGED
@@ -1,16 +1,17 @@
1
1
  require 'logger'
2
2
 
3
+ # Netdot
3
4
  module Netdot
4
-
5
5
  class << self
6
6
  attr_accessor :logger
7
7
  end
8
8
 
9
+ # NullLogger
9
10
  class NullLogger < Logger
10
- def initialize(*args)
11
+ def initialize(*_args)
11
12
  end
12
13
 
13
- def add(*args, &block)
14
+ def add(*_args, &_block)
14
15
  end
15
16
  end
16
17
 
@@ -19,4 +20,4 @@ end
19
20
 
20
21
  require 'netdot/restclient'
21
22
  require 'netdot/host'
22
- require 'netdot/subnet'
23
+ require 'netdot/ipblock'
data/lib/netdot/host.rb CHANGED
@@ -1,61 +1,68 @@
1
+ # Netdot
1
2
  module Netdot
3
+ # Manage Host objects.
2
4
  class Host
3
5
  attr_accessor :connection
4
6
 
7
+ # Constructor
8
+ # @param :connection [Hash] a Netdot::RestClient object
5
9
  def initialize(argv = {})
6
10
  [:connection].each do |k|
7
- raise ArgumentError, "Missing required argument '#{k}'" unless argv[k]
11
+ fail ArgumentError, "Missing required argument '#{k}'" unless argv[k]
8
12
  end
9
13
 
10
- argv.each { |k,v| instance_variable_set("@#{k}", v) }
14
+ argv.each { |k, v| instance_variable_set("@#{k}", v) }
11
15
  end
12
16
 
13
- ##############################################################
14
- # Find RR and Ipblock records with flexible arguments
15
- # Handle exceptions
17
+ # Finds all RR and Ipblock records, given a flexible set of arguments.
18
+ # Handles NOT FOUND exceptions.
19
+ # @param param [String] a generic parameter
20
+ # @param value [String] a generic value
16
21
  def find(param, value)
17
22
  begin
18
- host = @connection.get("/host?#{param.to_s}=#{value}");
19
- rescue Exception => e
23
+ host = @connection.get("/host?#{param}=#{value}")
24
+ rescue => e
20
25
  # Not Found is ok, otherwise re-raise
21
- raise unless (e.message =~ /404/)
26
+ raise unless e.message =~ /404/
22
27
  end
23
28
  # Return what we got
24
29
  host
25
30
  end
26
31
 
27
- ##############################################################
28
- # Find RR and Ipblock records associated with given name
32
+ # Finds all RR and Ipblock records associated with the specified name.
33
+ # @param name [String]
29
34
  def find_by_name(name)
30
35
  find(:name, name)
31
36
  end
32
37
 
33
- ##############################################################
34
- # Find RR and Ipblock records associated with this IP
38
+ # Finds all RR and Ipblock records associated with the specified IP.
39
+ # @param ip [String]
35
40
  def find_by_ip(ip)
36
41
  find(:address, ip)
37
42
  end
38
43
 
39
- ##############################################################
40
- # Create A record for given name and IP
41
- # Will also create PTR record if .arpa zone exists
44
+ # Creates a DNS A record for the specified name and IP.
45
+ # Will also create PTR record if .arpa zone exists.
46
+ # @param name [String]
47
+ # @param ip [String]
42
48
  def create(name, ip)
43
- Netdot.logger.debug("Creating new DNS records with name:#{name} and ip:#{ip}")
44
- @connection.post('host', {'name' => name, 'address' => ip})
49
+ Netdot.logger.debug("Creating new DNS records with name:#{name}" \
50
+ " and ip:#{ip}")
51
+ @connection.post('host', 'name' => name, 'address' => ip)
45
52
  end
46
53
 
47
- ##############################################################
48
- # Update A record for given name and IP
49
- # Will also create PTR record if .arpa zone exists
54
+ # Updates the DNS A record for the sepcified name and IP.
55
+ # Will also create PTR record if .arpa zone exists.
56
+ # @param name [String]
57
+ # @param ip [String]
50
58
  def update(name, ip)
51
59
  Netdot.logger.debug("Updating DNS records with name:#{name} and ip:#{ip}")
52
60
  delete(name)
53
- #delete_by_ip(ip)
54
61
  create(name, ip)
55
62
  end
56
63
 
57
- ##############################################################
58
- # Delete A record for given name
64
+ # Deletes the DNS A record for the specified name.
65
+ # @param name [String]
59
66
  def delete(name)
60
67
  host = find_by_name(name)
61
68
  return unless host
@@ -65,12 +72,11 @@ module Netdot
65
72
  host['Ipblock'].keys.each do |id|
66
73
  begin
67
74
  @connection.delete("host?ipid=#{id}")
68
- rescue Exception => e
75
+ rescue => e
69
76
  # Not Found is ok, otherwise re-raise
70
- raise unless (e.message =~ /404/)
77
+ raise unless e.message =~ /404/
71
78
  end
72
79
  end
73
80
  end
74
-
75
81
  end
76
82
  end
@@ -0,0 +1,118 @@
1
+ # Netdot
2
+ module Netdot
3
+ # Manage Ipblock objects.
4
+ class Ipblock
5
+ attr_accessor :connection
6
+
7
+ # Constructor
8
+ # @param :connection [Hash] a Netdot::RestClient object
9
+ def initialize(argv = {})
10
+ [:connection].each do |k|
11
+ fail ArgumentError, "Missing required argument '#{k}'" unless argv[k]
12
+ end
13
+
14
+ argv.each { |k, v| instance_variable_set("@#{k}", v) }
15
+ end
16
+
17
+ # Gets the next available Ipblock in the specified container.
18
+ # @param container [String] address
19
+ # @param prefix [Fixnum]
20
+ # @param description [String] (optional)
21
+ # @return [String] new Ipblock id, or nil
22
+ def allocate(container, prefix = 24, description = nil)
23
+ # Netdot currently only supports /24 prefixes
24
+ fail ArgumentError,
25
+ "Prefix size #{prefix} is not currently supported (must be 24)" \
26
+ unless prefix == 24
27
+
28
+ # Search for container and get its ID
29
+ cont_id = find_by_addr(container)
30
+
31
+ # Get container's children blocks
32
+ begin
33
+ resp = @connection.get("Ipblock?parent=#{cont_id}")
34
+ rescue => e
35
+ # Not Found is ok, otherwise re-raise
36
+ raise unless e.message =~ /404/
37
+ end
38
+
39
+ # store existing Ipblocks in hash (if any)
40
+ ipblocks = {}
41
+ if resp
42
+ resp.values.each do |b|
43
+ b.each do |_k, v|
44
+ address = v['address']
45
+ ipblocks[address] = 1
46
+ end
47
+ end
48
+ end
49
+
50
+ # Iterate over all possible Ipblocks
51
+ # This assumes that Ipblocks are /24
52
+ spref = container.split('/')[0]
53
+ spref.gsub!(/(\d+\.\d+)\..*/, '\1')
54
+
55
+ (1..255).each do |n|
56
+ spref.dup
57
+ saddr = spref + ".#{n}.0"
58
+ if !ipblocks.empty? && ipblocks.key?(saddr)
59
+ next # Ipblock exists
60
+ end
61
+
62
+ # Create Ipblock
63
+ args = {
64
+ 'address' => saddr,
65
+ 'prefix' => prefix.to_s,
66
+ 'status' => 'Subnet'
67
+ }
68
+ args['description'] = description unless description.nil?
69
+ resp = @connection.post('Ipblock', args)
70
+ return resp['address'] + '/' + resp['prefix']
71
+ end
72
+
73
+ fail "Could not allocate Ipblock in #{container}"
74
+ end
75
+
76
+ # Deletes an Ipblock (and optionally, all its children), for the specified
77
+ # address or CIDR.
78
+ # @param ipblock [String] address or CIDR
79
+ # @return (Truth)
80
+ def delete(ipblock, recursive = false)
81
+ if recursive
82
+ resp = @connection.get("host?subnet=#{ipblock}")
83
+ unless resp.empty?
84
+ resp['Ipblock'].keys.each do |id|
85
+ @connection.delete("Ipblock/#{id}")
86
+ end
87
+ end
88
+ end
89
+
90
+ sid = find_by_addr(ipblock)
91
+ @connection.delete("Ipblock/#{sid}")
92
+ end
93
+
94
+ # Gets the matching Ipblock id for the specified address (in CIDR format).
95
+ # @param cidr [String]
96
+ # @return [Ipblock]
97
+ def find_by_addr(cidr)
98
+ (address, prefix) = cidr.split('/')
99
+ prefix ||= '24'
100
+ begin
101
+ @connection.get("Ipblock?address=#{address}&prefix=#{prefix}")[
102
+ 'Ipblock'].keys[0]
103
+ rescue => e
104
+ raise unless e.message =~ /404/
105
+ end
106
+ end
107
+
108
+ # Gets an array of matching Ipblock ids for the specified description
109
+ # (name).
110
+ # @param descr [String]
111
+ # @return [Array<Ipblock>]
112
+ def find_by_descr(descr)
113
+ @connection.get("Ipblock?description=#{descr}")['Ipblock']
114
+ rescue => e
115
+ raise unless e.message =~ /404/
116
+ end
117
+ end
118
+ end
@@ -2,92 +2,83 @@ require 'netdot/restclient/version'
2
2
 
3
3
  require 'httpclient'
4
4
 
5
+ # Netdot
5
6
  module Netdot
6
- class RestClient
7
+ # Manage RestClient objects.
8
+ class RestClient
7
9
  attr_accessor :format, :base_url, :ua, :xs
8
10
 
9
11
  # Constructor and login method
10
- #
11
- # Arguments (hash):
12
- #
13
- # server - Netdot server URL
14
- # username - Netdot Username
15
- # password - Netdot password
16
- # retries - Number of attempts
17
- # timeout - Timeout in seconds
18
- # format - Content format <xml>
19
- # ssl_version - Specify version of SSL (see httpclient)
20
- # ssl_verify - Verify server cert (default: yes)
21
- # ssl_ca_file - Path to SSL CA cert file
22
- # ssl_ca_dir - Path to SSL CA cert directory
23
- # cookie_file - Cookie filename
24
- #
25
- # Returns:
26
- # Netdot::RestClient object
27
- # Example:
28
- # Netdot::Restclient.new(args)
29
- #
12
+ # @param :server [String] Netdot server URL
13
+ # @param :username [String] Netdot Username
14
+ # @param :password [String] Netdot password
15
+ # @param :retries [String] (optional) Number of attempts
16
+ # @param :timeout [String] (optional) Timeout in seconds
17
+ # @param :format [String] (optional) Content format <xml>
18
+ # @param :ssl_version [String] (optional) Specify version of SSL;
19
+ # see HTTPClient
20
+ # @param :ssl_verify [String] (optional) Verify server cert (default: yes)
21
+ # @param :ssl_ca_file [String] (optional) Path to SSL CA cert file
22
+ # @param :ssl_ca_dir [String] (optional) Path to SSL CA cert directory
23
+ # @param :cookie_file [String] (optional) Cookie filename
30
24
  def initialize(argv = {})
31
-
32
25
  [:server, :username, :password].each do |k|
33
- raise ArgumentError, "Missing required argument '#{k}'" unless argv[k]
26
+ fail ArgumentError, "Missing required argument '#{k}'" unless argv[k]
34
27
  end
35
-
36
- argv.each { |k,v| instance_variable_set("@#{k}", v) }
37
-
38
- @timeout ||= 10
39
- @retries ||= 3
40
- @format ||= 'xml'
28
+
29
+ argv.each { |k, v| instance_variable_set("@#{k}", v) }
30
+
31
+ @timeout ||= 10
32
+ @retries ||= 3
33
+ @format ||= 'xml'
41
34
  @cookie_file ||= './cookie.dat'
42
- defined?(@ssl_verify) or @ssl_verify = true
35
+ defined?(@ssl_verify) || @ssl_verify = true
43
36
 
44
- if ( @format == 'xml' )
37
+ if (@format == 'xml')
45
38
  begin
46
39
  require 'xmlsimple'
47
- rescue LoadError => e
48
- raise LoadError, "Cannot load XML library. Try running 'gem install xml-simple'"
40
+ rescue LoadError
41
+ raise LoadError,
42
+ "Cannot load XML library. Try running 'gem install xml-simple'"
49
43
  end
50
- xs = XmlSimple.new({ 'ForceArray' => true, 'KeyAttr' => 'id'})
44
+ xs = XmlSimple.new('ForceArray' => true, 'KeyAttr' => 'id')
51
45
  @xs = xs
52
46
  else
53
- raise ArgumentError, "Only XML formatting supported at this time"
47
+ fail ArgumentError, 'Only XML formatting supported at this time'
54
48
  end
55
49
 
56
- ua = HTTPClient.new(:agent_name => "Netdot::RestClient/#{self.version}")
50
+ ua = HTTPClient.new(agent_name: "Netdot::RestClient/#{version}")
57
51
  ua.set_cookie_store("#{@cookie_file}")
58
52
 
59
53
  # SSL stuff
60
- if ( @ssl_verify )
61
- if ( @ssl_ca_dir )
54
+ if @ssl_verify
55
+ if @ssl_ca_dir
62
56
  # We are told to add a certs path
63
57
  # We'll want to clear the default cert store first
64
58
  ua.ssl_config.clear_cert_store
65
59
  ua.ssl_config.set_trust_ca(@ssl_ca_dir)
66
- elsif ( @ssl_ca_file )
67
- ua.ssl_config.set_trust_ca(@ssl_ca_file)
60
+ elsif @ssl_ca_file
61
+ ua.ssl_config.set_trust_ca(@ssl_ca_file)
68
62
  end
69
63
  else
70
64
  ua.ssl_config.verify_mode = OpenSSL::SSL::VERIFY_NONE
71
65
  end
72
66
 
73
67
  # If version given, set it
74
- if ( @ssl_version )
75
- ua.ssl_config.ssl_version = @ssl_version
76
- end
68
+ ua.ssl_config.ssl_version = @ssl_version if @ssl_version
77
69
 
78
70
  login_url = @server + '/NetdotLogin'
79
-
71
+
80
72
  resp = nil
81
73
 
82
74
  @retries.times do
83
- resp = ua.post login_url, {
84
- 'destination' => 'index.html',
85
- 'credential_0' => @username,
86
- 'credential_1' => @password,
87
- 'permanent_session' => 1,
88
- }
89
-
90
- if ( resp.status == 302 )
75
+ resp = ua.post login_url,
76
+ 'destination' => 'index.html',
77
+ 'credential_0' => @username,
78
+ 'credential_1' => @password,
79
+ 'permanent_session' => 1
80
+
81
+ if (resp.status == 302)
91
82
  ua.save_cookie_store
92
83
  @ua = ua
93
84
  @base_url = @server + '/rest'
@@ -97,82 +88,61 @@ module Netdot
97
88
  end
98
89
  end
99
90
 
100
- unless ( resp.status == 302 )
101
- raise "Could not log into #{@server}. Status Code: '#{resp.status}'"
102
- end
103
-
91
+ return if (resp.status == 302)
92
+ fail "Could not log into #{@server}. Status Code: '#{resp.status}'"
104
93
  end
105
-
106
94
 
107
- # Build the Extra headers
108
- #
95
+ # Builds the Extra headers.
109
96
  def extheader
110
- { 'Accept' => 'text/' + self.format + '; version=1.0' }
97
+ { 'Accept' => 'text/' + format + '; version=1.0' }
111
98
  end
112
99
 
113
- # Build URL given a resource
114
- #
100
+ # Builds a URL for the specified resource.
101
+ # @param [String] resource a URI
115
102
  def build_url(resource)
116
- self.base_url + '/' + resource
103
+ base_url + '/' + resource
117
104
  end
118
105
 
119
- # Get a resource
120
- #
121
- # Arguments:
122
- # resource - A URI
123
- # Returns:
124
- # hash when successful
125
- # exception when not
106
+ # Gets a resource.
107
+ # @param [String] resource a URI
108
+ # @return [Hash] hash when successful; exception when not
126
109
  def get(resource)
127
- url = self.build_url(resource)
128
- resp = self.ua.get(url, nil, self.extheader)
129
- if ( resp.status == 200 )
130
- self.xs.xml_in(resp.content)
110
+ url = build_url(resource)
111
+ resp = ua.get(url, nil, extheader)
112
+ if (resp.status == 200)
113
+ xs.xml_in(resp.content)
131
114
  else
132
- raise "Could not get #{url}: #{resp.status}"
115
+ fail "Could not get #{url}: #{resp.status}"
133
116
  end
134
117
  end
135
118
 
136
-
137
- # Update or create a resource
138
- #
139
- # Arguments:
140
- # resource - A URI
141
- # data - Hash with key/values
142
- # Returns:
143
- # new or modified record hash when successful
144
- # exception when not
119
+ # Updates or creates a resource.
120
+ # @param [String] resource a URI
121
+ # @param [Hash] data
122
+ # @return [Hash] new or modified record hash when successful; exception
123
+ # when not
145
124
  def post(resource, data)
146
- url = self.build_url(resource)
147
- raise ArgumentError, "Data must be hash" unless data.is_a?(Hash)
148
- resp = self.ua.post(url, data, self.extheader)
149
- if ( resp.status == 200 )
150
- self.xs.xml_in(resp.content)
125
+ url = build_url(resource)
126
+ fail ArgumentError, 'Data must be hash' unless data.is_a?(Hash)
127
+ resp = ua.post(url, data, extheader)
128
+ if (resp.status == 200)
129
+ xs.xml_in(resp.content)
151
130
  else
152
- raise "Could not post to #{url}: #{resp.status}"
131
+ fail "Could not post to #{url}: #{resp.status}"
153
132
  end
154
133
  end
155
134
 
156
-
157
- # Delete a resource
158
- #
159
- # Arguments:
160
- # resource - A URI
161
- #
162
- # Returns:
163
- # true when successful
164
- # exception when not
165
- #
135
+ # Deletes a resource.
136
+ # @param [String] resource a URI
137
+ # @return [Truth] true when successful; exception when not
166
138
  def delete(resource)
167
- url = self.build_url(resource)
168
- resp = self.ua.delete(url, nil, self.extheader)
169
- if ( resp.status == 200 )
139
+ url = build_url(resource)
140
+ resp = ua.delete(url, nil, extheader)
141
+ if (resp.status == 200)
170
142
  return true
171
143
  else
172
- raise "Could not delete #{url}: #{resp.status}"
144
+ fail "Could not delete #{url}: #{resp.status}"
173
145
  end
174
-
175
146
  end
176
-
177
147
  end
178
148
  end