netdot-restclient 1.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/.gitignore ADDED
@@ -0,0 +1,25 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ *.bundle
19
+ *.so
20
+ *.o
21
+ *.a
22
+ mkmf.log
23
+ *~
24
+ cookie.dat
25
+
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in netdot-restclient.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,13 @@
1
+ Copyright (c) 2014 Carlos Vicente
2
+
3
+ Licensed under the Apache License, Version 2.0 (the "License");
4
+ you may not use this file except in compliance with the License.
5
+ You may obtain a copy of the License at
6
+
7
+ http://www.apache.org/licenses/LICENSE-2.0
8
+
9
+ Unless required by applicable law or agreed to in writing, software
10
+ distributed under the License is distributed on an "AS IS" BASIS,
11
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ See the License for the specific language governing permissions and
13
+ limitations under the License.
data/README.md ADDED
@@ -0,0 +1,59 @@
1
+ # Netdot::RestClient
2
+
3
+ RESTful API Ruby client for the Network Documentation Tool
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'netdot-restclient'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install netdot-restclient
18
+
19
+ ## Usage
20
+
21
+ require 'netdot-restclient'
22
+ require 'pp'
23
+
24
+ netdot = Netdot::RestClient.new(
25
+ :server => 'http://localhost.localdomain/netdot',
26
+ :username => 'admin',
27
+ :password => 'xxxxx',
28
+ )
29
+
30
+ # Get all devices
31
+ devs = netdot.get('/Device');
32
+
33
+ pp devs
34
+
35
+ # Get Device id 1
36
+ dev = netdot.get('/Device/1');
37
+
38
+ # Get Device id 1 and foreign objects one level away
39
+ dev = netdot.get('/Device/1?depth=1');
40
+
41
+ # Update Device 1
42
+ dev = netdot.post('/Device/1', {community=>'public'});
43
+
44
+ # Delete Device 1
45
+ netdot.delete('/Device/1');
46
+
47
+ ## See Also
48
+
49
+ The Netdot user manual at:
50
+
51
+ http://netdot.uoregon.edu
52
+
53
+ ## Contributing
54
+
55
+ 1. Fork it ( https://github.com/cvicente/netdot-restclient/fork )
56
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
57
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
58
+ 4. Push to the branch (`git push origin my-new-feature`)
59
+ 5. Create a new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ require "bundler/gem_tasks"
2
+
@@ -0,0 +1,149 @@
1
+ require 'netdot/restclient/version'
2
+
3
+ require 'httpclient'
4
+
5
+ module Netdot
6
+ class RestClient
7
+ attr_accessor :format, :base_url, :ua, :xs
8
+
9
+ # 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
+ #
20
+ # Returns:
21
+ # Netdot::RestClient object
22
+ # Example:
23
+ # Netdot::Restclient.new(args)
24
+ #
25
+ def initialize(argv = {})
26
+
27
+ [:server, :username, :password].each do |k|
28
+ raise ArgumentError, "Missing required argument '#{k}'" unless argv[k]
29
+ end
30
+
31
+ argv.each { |k,v| instance_variable_set("@#{k}", v) }
32
+
33
+ @timeout ||= 10
34
+ @retries ||= 3
35
+ @format ||= 'xml'
36
+
37
+ if ( @format == 'xml' )
38
+ begin
39
+ require 'xmlsimple'
40
+ rescue LoadError => e
41
+ raise LoadError, "Cannot load XML library. Try running 'gem install xml-simple'"
42
+ end
43
+ xs = XmlSimple.new({ 'ForceArray' => true, 'KeyAttr' => 'id'})
44
+ @xs = xs
45
+ else
46
+ raise ArgumentError, "Only XML formatting supported at this time"
47
+ end
48
+
49
+ ua = HTTPClient.new(:agent_name => "Netdot::RestClient/#{self.version}")
50
+ ua.set_cookie_store("cookie.dat")
51
+
52
+ login_url = @server + '/NetdotLogin'
53
+
54
+ resp = nil
55
+
56
+ @retries.times do
57
+ resp = ua.post login_url, {
58
+ 'destination' => 'index.html',
59
+ 'credential_0' => @username,
60
+ 'credential_1' => @password,
61
+ 'permanent_session' => 1,
62
+ }
63
+ if resp
64
+ ua.save_cookie_store
65
+ @ua = ua
66
+ @base_url = @server + '/rest'
67
+ break
68
+ else
69
+ $stderr.puts "Connection attempt to #{@server} failed"
70
+ end
71
+ end
72
+
73
+ raise "Could not log into #{@server}" unless resp
74
+
75
+ end
76
+
77
+
78
+ # Build the Extra headers
79
+ #
80
+ def extheader
81
+ { 'Accept' => 'text/' + self.format + '; version=1.0' }
82
+ end
83
+
84
+ # Build URL given a resource
85
+ #
86
+ def build_url(resource)
87
+ self.base_url + '/' + resource
88
+ end
89
+
90
+ # Get a resource
91
+ #
92
+ # Arguments:
93
+ # resource - A URI
94
+ # Returns:
95
+ # hash when successful
96
+ # exception when not
97
+ def get(resource)
98
+ url = self.build_url(resource)
99
+ resp = self.ua.get(url, nil, self.extheader)
100
+ if ( resp.status == 200 )
101
+ self.xs.xml_in(resp.content)
102
+ else
103
+ raise "Could not get #{url}: #{resp.status}"
104
+ end
105
+ end
106
+
107
+
108
+ # Update or create a resource
109
+ #
110
+ # Arguments:
111
+ # resource - A URI
112
+ # data - Hash with key/values
113
+ # Returns:
114
+ # new or modified record hash when successful
115
+ # exception when not
116
+ def post(resource, data)
117
+ url = self.build_url(resource)
118
+ raise ArgumentError, "Data must be hash" unless data.is_a?(Hash)
119
+ resp = self.ua.post(url, data, self.extheader)
120
+ if ( resp.status == 200 )
121
+ self.xs.xml_in(resp.content)
122
+ else
123
+ raise "Could not post to #{url}: #{resp.status}"
124
+ end
125
+ end
126
+
127
+
128
+ # Delete a resource
129
+ #
130
+ # Arguments:
131
+ # resource - A URI
132
+ #
133
+ # Returns:
134
+ # true when successful
135
+ # exception when not
136
+ #
137
+ def delete(resource)
138
+ url = self.build_url(resource)
139
+ resp = self.ua.delete(url, nil, self.extheader)
140
+ if ( resp.status == 200 )
141
+ return true
142
+ else
143
+ raise "Could not delete #{url}: #{resp.status}"
144
+ end
145
+
146
+ end
147
+
148
+ end
149
+ end
@@ -0,0 +1,10 @@
1
+ module Netdot
2
+ class RestClient
3
+ VERSION = "1.0"
4
+
5
+ def version
6
+ VERSION
7
+ end
8
+
9
+ end
10
+ end
@@ -0,0 +1,28 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'netdot/restclient/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "netdot-restclient"
8
+ spec.version = Netdot::RestClient::VERSION
9
+ spec.authors = ["Carlos Vicente"]
10
+ spec.email = ["cvicente@gmail.com"]
11
+ spec.summary = %q{RESTful API client for Netdot}
12
+ spec.description = %q{Talk to Netdot via REST with Ruby}
13
+ spec.homepage = ""
14
+ spec.license = "Apache-2.0"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.6"
22
+ spec.add_development_dependency "rake"
23
+ spec.add_development_dependency "rspec", "~> 2.6"
24
+
25
+ spec.add_dependency "httpclient"
26
+ spec.add_dependency "xml-simple"
27
+
28
+ end
data/sample/host.rb ADDED
@@ -0,0 +1,36 @@
1
+ #
2
+ # Example: Use the special-purpose 'host' resource
3
+ # to allocate a new IP and assign DNS records
4
+ #
5
+ #
6
+ require 'netdot/restclient'
7
+
8
+ require 'pp'
9
+
10
+ netdot = Netdot::RestClient.new(
11
+ :server => 'http://localhost/netdot',
12
+ :username => 'admin',
13
+ :password => 'admin',
14
+ )
15
+ # Add
16
+ # This allocates the first available IP in the given subnet
17
+ # and creates A and PTR records, assuming that the subnet
18
+ # is associated with the appropriate forward and reverse zones
19
+ netdot.post('host', { 'name' => 'testhost1', 'subnet' => '192.168.1.0/24'})
20
+
21
+ # Find
22
+ resp = netdot.get('host?name=testhost1.defaultdomain')
23
+
24
+ pp resp
25
+
26
+ ipid = resp['Ipblock'].keys[0]
27
+
28
+ # Delete DNS records associated with new IP
29
+ netdot.delete("host?ipid=#{ipid}")
30
+
31
+ # Notice that the above does not delete the Ipblock object, but
32
+ # marks it as "available"
33
+ # If user has admin privileges and really wants to delete the
34
+ # Ipblock, then they can do:
35
+
36
+ netdot.delete("Ipblock/#{ipid}")
@@ -0,0 +1,94 @@
1
+ require 'netdot/restclient'
2
+
3
+ describe Netdot::RestClient do
4
+ before :all do
5
+ args = {
6
+ username: 'admin',
7
+ server: 'http://localhost/netdot'
8
+ }
9
+ expect {
10
+ Netdot::RestClient.new(args)
11
+ }.to raise_error(ArgumentError)
12
+
13
+ args[:password] = 'admin'
14
+ @netdot = Netdot::RestClient.new(args)
15
+ expect(@netdot).to be_an_instance_of(Netdot::RestClient)
16
+
17
+ end
18
+
19
+ context 'when getting' do
20
+
21
+ it 'invalid resource raises exception' do
22
+ expect {
23
+ resp = @netdot.get('foobar')
24
+ }.to raise_error
25
+ end
26
+
27
+ it 'valid resource as hash' do
28
+ resp = @netdot.get('Entity/1')
29
+ resp.should be_an_instance_of(Hash)
30
+ end
31
+
32
+ it 'record by id' do
33
+ resp = @netdot.get('Entity/1')
34
+ expect(resp['name']).to eq('Unknown')
35
+ end
36
+
37
+ it 'records filtered by name' do
38
+ resp = @netdot.get('Entity?name=Unknown')
39
+ expect(resp['Entity']['1']['name']).to eq('Unknown')
40
+ end
41
+
42
+
43
+ end
44
+
45
+ context 'when posting' do
46
+
47
+ it 'fails to update invalid record' do
48
+ expect {
49
+ resp = @netdot.post('Foobar/1', {'key' => 'value'} )
50
+ }.to raise_error
51
+ end
52
+
53
+ it 'creates new record' do
54
+ resp = @netdot.post('Person',
55
+ { 'firstname' => 'Joe',
56
+ 'lastname' => 'Plumber',
57
+ 'username' => 'joetubes'
58
+ })
59
+ expect(resp['firstname']).to eq ('Joe')
60
+ expect(resp['lastname']).to eq ('Plumber')
61
+
62
+ end
63
+
64
+ it 'fails to create duplicate record' do
65
+ expect {
66
+ resp = @netdot.post('Person',
67
+ { 'firstname' => 'Joe',
68
+ 'lastname' => 'Plumber',
69
+ 'username' => 'joetubes'
70
+ })
71
+ }.to raise_error
72
+ end
73
+
74
+ end
75
+
76
+ context 'when deleting' do
77
+
78
+ it 'fails to delete invalid record' do
79
+ expect {
80
+ resp = @netdot.delete('FooBar/1234')
81
+ }.to raise_error
82
+ end
83
+
84
+ it 'deletes exiting record' do
85
+ resp = @netdot.get('Person?lastname=Plumber')
86
+ person_id = resp['Person'].keys[0]
87
+ resp = @netdot.delete("Person/#{person_id}")
88
+ expect(resp).to be_true
89
+ end
90
+
91
+ end
92
+
93
+ end
94
+
metadata ADDED
@@ -0,0 +1,112 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: netdot-restclient
3
+ version: !ruby/object:Gem::Version
4
+ version: '1.0'
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Carlos Vicente
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2014-04-09 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: bundler
16
+ requirement: &83415360 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: '1.6'
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: *83415360
25
+ - !ruby/object:Gem::Dependency
26
+ name: rake
27
+ requirement: &83414820 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ! '>='
31
+ - !ruby/object:Gem::Version
32
+ version: '0'
33
+ type: :development
34
+ prerelease: false
35
+ version_requirements: *83414820
36
+ - !ruby/object:Gem::Dependency
37
+ name: rspec
38
+ requirement: &83414210 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ~>
42
+ - !ruby/object:Gem::Version
43
+ version: '2.6'
44
+ type: :development
45
+ prerelease: false
46
+ version_requirements: *83414210
47
+ - !ruby/object:Gem::Dependency
48
+ name: httpclient
49
+ requirement: &83413860 !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ! '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ type: :runtime
56
+ prerelease: false
57
+ version_requirements: *83413860
58
+ - !ruby/object:Gem::Dependency
59
+ name: xml-simple
60
+ requirement: &83413340 !ruby/object:Gem::Requirement
61
+ none: false
62
+ requirements:
63
+ - - ! '>='
64
+ - !ruby/object:Gem::Version
65
+ version: '0'
66
+ type: :runtime
67
+ prerelease: false
68
+ version_requirements: *83413340
69
+ description: Talk to Netdot via REST with Ruby
70
+ email:
71
+ - cvicente@gmail.com
72
+ executables: []
73
+ extensions: []
74
+ extra_rdoc_files: []
75
+ files:
76
+ - .gitignore
77
+ - Gemfile
78
+ - LICENSE.txt
79
+ - README.md
80
+ - Rakefile
81
+ - lib/netdot/restclient.rb
82
+ - lib/netdot/restclient/version.rb
83
+ - netdot-restclient.gemspec
84
+ - sample/host.rb
85
+ - spec/restclient_spec.rb
86
+ homepage: ''
87
+ licenses:
88
+ - Apache-2.0
89
+ post_install_message:
90
+ rdoc_options: []
91
+ require_paths:
92
+ - lib
93
+ required_ruby_version: !ruby/object:Gem::Requirement
94
+ none: false
95
+ requirements:
96
+ - - ! '>='
97
+ - !ruby/object:Gem::Version
98
+ version: '0'
99
+ required_rubygems_version: !ruby/object:Gem::Requirement
100
+ none: false
101
+ requirements:
102
+ - - ! '>='
103
+ - !ruby/object:Gem::Version
104
+ version: '0'
105
+ requirements: []
106
+ rubyforge_project:
107
+ rubygems_version: 1.8.11
108
+ signing_key:
109
+ specification_version: 3
110
+ summary: RESTful API client for Netdot
111
+ test_files:
112
+ - spec/restclient_spec.rb