netdot-restclient 1.4 → 2.0.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.
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