netdot-restclient 1.0

Sign up to get free protection for your applications and to get access to all the features.
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