junos-space-api 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +21 -0
- data/README.md +41 -0
- data/examples/add_device.rb +19 -0
- data/examples/addresses.rb +29 -0
- data/examples/jobs.rb +18 -0
- data/examples/sec_device.rb +12 -0
- data/examples/services.rb +26 -0
- data/junos-space-api.gemspec +13 -0
- data/lib/junos-space-api/platform.rb +2 -0
- data/lib/junos-space-api/platform/device.rb +106 -0
- data/lib/junos-space-api/platform/job.rb +87 -0
- data/lib/junos-space-api/sd.rb +3 -0
- data/lib/junos-space-api/sd/address.rb +176 -0
- data/lib/junos-space-api/sd/device.rb +114 -0
- data/lib/junos-space-api/sd/service.rb +175 -0
- data/lib/junos-space-api/space.rb +20 -0
- metadata +62 -0
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2013 Scott Ware
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all 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,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
## junos-ruby-space-api
|
2
|
+
|
3
|
+
This program is used to interact with the Junos Space REST API, using Ruby. The following additional
|
4
|
+
gems are required:
|
5
|
+
|
6
|
+
- `rest-client`
|
7
|
+
- `nokogiri`
|
8
|
+
- `ipaddress`
|
9
|
+
|
10
|
+
These can all be installed by issuing `gem install <gem>` on the command line.
|
11
|
+
|
12
|
+
### Web Services Available
|
13
|
+
|
14
|
+
Here are the current web services available so far in this API:
|
15
|
+
|
16
|
+
*Platform*
|
17
|
+
|
18
|
+
- Job Management
|
19
|
+
- Device Management
|
20
|
+
|
21
|
+
*Security Director*
|
22
|
+
|
23
|
+
- Address Management
|
24
|
+
- Service Management
|
25
|
+
- Device Management
|
26
|
+
|
27
|
+
Please see [Juniper's documentation][2] for the full release notes on the Security Director API.
|
28
|
+
|
29
|
+
I will be adding more functionality/web services soon, so please keep checking back!
|
30
|
+
|
31
|
+
### Documentation & Usage
|
32
|
+
|
33
|
+
Check out the [Wiki][1] for documentation on the different Classes and their respective methods.
|
34
|
+
|
35
|
+
### Examples
|
36
|
+
|
37
|
+
Check out the `examples` directory to browse through some samples of what this API can do!
|
38
|
+
|
39
|
+
|
40
|
+
[1]: https://github.com/scottdware/junos-ruby-space-api/wiki
|
41
|
+
[2]: http://www.juniper.net/techpubs/en_US/junos-space13.1/information-products/topic-collections/junos-space-security-designer/security-director-api.pdf
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'junos-space-api/platform'
|
2
|
+
require 'pp'
|
3
|
+
|
4
|
+
user = 'me'
|
5
|
+
pass = 'somepass'
|
6
|
+
server = 'space.company.com'
|
7
|
+
|
8
|
+
JunosSpace.open('user', 'pass', 'server')
|
9
|
+
devices = JunosSpace::Platform::Device.new
|
10
|
+
|
11
|
+
data = {
|
12
|
+
'host' => '10.10.10.1',
|
13
|
+
'snmp' => 'false',
|
14
|
+
'user' => 'sshuser',
|
15
|
+
'pass' => 'sshpass'
|
16
|
+
}
|
17
|
+
|
18
|
+
# Will return the job ID (i.e. {"status"=>"9990001"}
|
19
|
+
pp devices.add_device(data)
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'junos-space-api/sd'
|
2
|
+
require 'pp'
|
3
|
+
|
4
|
+
user = 'me'
|
5
|
+
pass = 'somepass'
|
6
|
+
server = 'space.company.com'
|
7
|
+
|
8
|
+
JunosSpace.open('user', 'pass', 'server')
|
9
|
+
addrs = JunosSpace::SD::Address.new
|
10
|
+
|
11
|
+
data = {
|
12
|
+
'name' => 'my-home-network',
|
13
|
+
'type' => 'network',
|
14
|
+
'ip' => '192.168.1.0/24',
|
15
|
+
'desc' => 'My home network',
|
16
|
+
'version' => 'v4'
|
17
|
+
}
|
18
|
+
|
19
|
+
# Will get a list of all of the address objects.
|
20
|
+
pp addrs.addresses
|
21
|
+
|
22
|
+
# Will add a new address object to Junos Space.
|
23
|
+
pp addrs.add_address(data)
|
24
|
+
|
25
|
+
# Will return information about the address object.
|
26
|
+
pp addrs.address_info('my-home-network')
|
27
|
+
|
28
|
+
# Will delete the address object.
|
29
|
+
pp addrs.delete_address('my-home-network')
|
data/examples/jobs.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'junos-space-api/platform'
|
2
|
+
require 'pp'
|
3
|
+
|
4
|
+
user = 'me'
|
5
|
+
pass = 'somepass'
|
6
|
+
server = 'space.company.com'
|
7
|
+
|
8
|
+
JunosSpace.open('user', 'pass', 'server')
|
9
|
+
jobs = JunosSpace::Platform::Job.new
|
10
|
+
|
11
|
+
# Will return all jobs with a status of SUCCESS
|
12
|
+
pp jobs.jobs('success')
|
13
|
+
|
14
|
+
# Will return all jobs with a status of FAILURE
|
15
|
+
pp jobs.jobs('failure')
|
16
|
+
|
17
|
+
# Will return information about the job ID 9990001
|
18
|
+
pp jobs.job_info('9990001')
|
@@ -0,0 +1,12 @@
|
|
1
|
+
require 'junos-space-api/sd'
|
2
|
+
require 'pp'
|
3
|
+
|
4
|
+
user = 'me'
|
5
|
+
pass = 'somepass'
|
6
|
+
server = 'space.company.com'
|
7
|
+
|
8
|
+
JunosSpace.open('user', 'pass', 'server')
|
9
|
+
secdev = JunosSpace::SD::Device.new
|
10
|
+
|
11
|
+
# Will return the security device information (i.e. zones, interfaces, etc.)
|
12
|
+
pp secdev.device_info('corporate-firewall')
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'junos-space-api/sd'
|
2
|
+
require 'pp'
|
3
|
+
|
4
|
+
user = 'me'
|
5
|
+
pass = 'somepass'
|
6
|
+
server = 'space.company.com'
|
7
|
+
|
8
|
+
JunosSpace.open('user', 'pass', 'server')
|
9
|
+
services = JunosSpace::SD::Service.new
|
10
|
+
|
11
|
+
data = {
|
12
|
+
'name' => 'my-custom-service',
|
13
|
+
'port' => '60001'
|
14
|
+
}
|
15
|
+
|
16
|
+
# Will get a list of all of the services.
|
17
|
+
pp services.services
|
18
|
+
|
19
|
+
# Will add a new service object to Junos Space.
|
20
|
+
pp services.add_service(data)
|
21
|
+
|
22
|
+
# Will return information about the service object.
|
23
|
+
pp services.service_info('my-custom-service')
|
24
|
+
|
25
|
+
# Will delete the service object.
|
26
|
+
pp services.delete_service('my-custom-service')
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'rake'
|
2
|
+
|
3
|
+
Gem::Specification.new do |s|
|
4
|
+
s.license = 'MIT'
|
5
|
+
s.name = 'junos-space-api'
|
6
|
+
s.version = '0.2.0'
|
7
|
+
s.summary = 'Interact with the Junos Space REST API.'
|
8
|
+
s.description = 'This gem is used to interact with Juniper Networks Junos Space management platform using the REST API.'
|
9
|
+
s.authors = ["Scott Ware"]
|
10
|
+
s.email = 'scottdware@gmail.com'
|
11
|
+
s.files = FileList['*', 'lib/**/*.rb', 'examples/*.rb']
|
12
|
+
s.homepage = 'https://github.com/scottdware/junos-ruby-space-api'
|
13
|
+
end
|
@@ -0,0 +1,106 @@
|
|
1
|
+
require 'rest-client'
|
2
|
+
require 'nokogiri'
|
3
|
+
require 'ipaddress'
|
4
|
+
require 'junos-space-api/space'
|
5
|
+
|
6
|
+
class JunosSpace::Platform::Device
|
7
|
+
@@devices_uri = '/api/space/device-management/devices'
|
8
|
+
@@discover_uri = '/api/space/device-management/discover-devices'
|
9
|
+
@@device_headers = {
|
10
|
+
:content_type => 'application/vnd.net.juniper.space.device-management.discover-devices+xml;version=2;charset=UTF-8'
|
11
|
+
}
|
12
|
+
@@queue_headers = {
|
13
|
+
:content_type => 'application/hornetq.jms.queue+xml'
|
14
|
+
}
|
15
|
+
@@ucase = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
|
16
|
+
@@dcase = 'abcdefghijklmnopqrstuvwxyz'
|
17
|
+
|
18
|
+
# devices
|
19
|
+
#
|
20
|
+
# Returns a Hash of all of the devices in the Junos Space database. The
|
21
|
+
# device name is the key, and value is an array of the following:
|
22
|
+
# device id, family, Junos version, platform, serial number,
|
23
|
+
# connection status, IP address, and managed status.
|
24
|
+
#
|
25
|
+
def devices
|
26
|
+
result = {}
|
27
|
+
|
28
|
+
begin
|
29
|
+
res = RestClient.get("#{JunosSpace.base_uri}#{@@devices_uri}")
|
30
|
+
doc = Nokogiri::XML::Document.parse(res)
|
31
|
+
|
32
|
+
doc.xpath('//device').each do |device|
|
33
|
+
stats = []
|
34
|
+
stats << device.xpath('@key').text
|
35
|
+
stats << device.xpath('deviceFamily').text
|
36
|
+
stats << device.xpath('OSVersion').text
|
37
|
+
stats << device.xpath('platform').text
|
38
|
+
stats << device.xpath('serialNumber').text
|
39
|
+
stats << device.xpath('connectionStatus').text
|
40
|
+
stats << device.xpath('ipAddr').text
|
41
|
+
stats << device.xpath('managedStatus').text
|
42
|
+
|
43
|
+
result[device.xpath('name').text] = stats
|
44
|
+
end
|
45
|
+
|
46
|
+
return result
|
47
|
+
rescue RestClient::Unauthorized
|
48
|
+
result['status'] = '401 Error - Auth failure (bad username/password).'
|
49
|
+
|
50
|
+
return result
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
# add_device(data)
|
55
|
+
#
|
56
|
+
# Add a new device to the Junos Space database, with the given information
|
57
|
+
# in 'data'. 'data' is a Hash table with the following structure:
|
58
|
+
#
|
59
|
+
# `host => IP address or hostname of device`,
|
60
|
+
# `snmp => Use SNMP during discovery: 'community string' or 'false'`,
|
61
|
+
# `user => SSH username for device`,
|
62
|
+
# `pass => SSH password for device`
|
63
|
+
#
|
64
|
+
# Returns a Hash with 'status' as the key, and the job ID as the value.
|
65
|
+
#
|
66
|
+
def add_device(data)
|
67
|
+
result = {}
|
68
|
+
|
69
|
+
begin
|
70
|
+
rand = Random.rand(999999)
|
71
|
+
server = JunosSpace.base_uri.split('@')[1]
|
72
|
+
queue_xml = "<queue name='d#{rand}'><durable>false</durable></queue>"
|
73
|
+
RestClient.post("#{JunosSpace.base_uri}/api/hornet-q/queues", queue_xml, @@queue_headers)
|
74
|
+
queue_url = "https://#{server}/api/hornet-q/queues/jms.queue.d#{rand}"
|
75
|
+
|
76
|
+
xml = "<discover-devices>"
|
77
|
+
|
78
|
+
if IPAddress.valid?(data['host'])
|
79
|
+
xml += "<ipAddressDiscoveryTarget><ipAddress>#{data['host']}</ipAddress></ipAddressDiscoveryTarget>"
|
80
|
+
else
|
81
|
+
xml += "<hostNameDiscoveryTarget><hostName>#{data['host']}</hostName></hostNameDiscoveryTarget>"
|
82
|
+
end
|
83
|
+
|
84
|
+
if data['snmp'] != 'false'
|
85
|
+
xml += "<useSnmp>true</useSnmp><snmpV1Setting><communityName>#{data['snmp']}</communityName></snmpV1Setting>"
|
86
|
+
else
|
87
|
+
xml += "<manageDiscoveredSystemsFlag>true</manageDiscoveredSystemsFlag><sshCredential>" +
|
88
|
+
"<userName>#{data['user']}</userName><password>#{data['pass']}</password></sshCredential>" +
|
89
|
+
"</discover-devices>"
|
90
|
+
end
|
91
|
+
|
92
|
+
res = RestClient.post("#{JunosSpace.base_uri}#{@@discover_uri}?queue-url=#{queue_url}", xml, @@device_headers)
|
93
|
+
doc = Nokogiri::XML::Document.parse(res)
|
94
|
+
|
95
|
+
if res.code == 202
|
96
|
+
result['status'] = doc.xpath('//task/id').text
|
97
|
+
end
|
98
|
+
|
99
|
+
return result
|
100
|
+
rescue RestClient::Unauthorized
|
101
|
+
result['status'] = '401 Error - Auth failure (bad username/password).'
|
102
|
+
|
103
|
+
return result
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
require 'rest-client'
|
2
|
+
require 'nokogiri'
|
3
|
+
require 'junos-space-api/space'
|
4
|
+
|
5
|
+
class JunosSpace::Platform::Job
|
6
|
+
@@job_uri = '/api/space/job-management/jobs'
|
7
|
+
@@ucase = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
|
8
|
+
@@dcase = 'abcdefghijklmnopqrstuvwxyz'
|
9
|
+
|
10
|
+
# jobs(status)
|
11
|
+
#
|
12
|
+
# Returns a Hash of all of the jobs in Space with the status
|
13
|
+
# 'status'. Where 'status' can be one of: 'success', 'failure',
|
14
|
+
# 'inprogress', or 'cancelled'. If no status is given, then all of the jobs are
|
15
|
+
# returned. The name of the job is the key, and the ID is the value.
|
16
|
+
#
|
17
|
+
def jobs(status)
|
18
|
+
result = {}
|
19
|
+
|
20
|
+
begin
|
21
|
+
res = RestClient.get("#{JunosSpace.base_uri}#{@@job_uri}")
|
22
|
+
doc = Nokogiri::XML::Document.parse(res)
|
23
|
+
|
24
|
+
if status
|
25
|
+
doc.xpath("//job[contains(translate(status, '#{@@ucase}', '#{@@dcase}'), translate('#{status}', '#{@@ucase}', '#{@@dcase}'))]").each do |job|
|
26
|
+
name = job.xpath('name').text
|
27
|
+
id = job.xpath('@key').text
|
28
|
+
|
29
|
+
result[name] = id
|
30
|
+
end
|
31
|
+
|
32
|
+
if result.size == 0
|
33
|
+
result['status'] = "No jobs found with status: #{status.downcase}."
|
34
|
+
end
|
35
|
+
else
|
36
|
+
doc.xpath("//job").each do |job|
|
37
|
+
name = job.xpath('name').text
|
38
|
+
id = job.xpath('@key').text
|
39
|
+
|
40
|
+
result[name] = id
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
return result
|
45
|
+
rescue RestClient::Unauthorized
|
46
|
+
result['status'] = '401 Error - Auth failure (bad username/password).'
|
47
|
+
|
48
|
+
return result
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
# job_info(job)
|
53
|
+
#
|
54
|
+
# Returns information about the job 'job'. This information is returned in a Hash
|
55
|
+
# with the job ID, name, percentage complete, status, job type, summary, user
|
56
|
+
# who issued the job, and the time the job was started.
|
57
|
+
#
|
58
|
+
def job_info(job)
|
59
|
+
result = {}
|
60
|
+
|
61
|
+
begin
|
62
|
+
res = RestClient.get("#{JunosSpace.base_uri}#{@@job_uri}/#{job}")
|
63
|
+
doc = Nokogiri::XML::Document.parse(res)
|
64
|
+
|
65
|
+
doc.xpath('//job').each do |job|
|
66
|
+
result["id"] = job.xpath('id').text
|
67
|
+
result["name"] = job.xpath('name').text
|
68
|
+
result["percent"] = job.xpath('percent').text
|
69
|
+
result["status"] = job.xpath('status').text
|
70
|
+
result["job-type"] = job.xpath('jobType').text
|
71
|
+
result["summary"] = job.xpath('summary').text
|
72
|
+
result["time"] = job.xpath('scheduledStartTime').text
|
73
|
+
result["user"] = job.xpath('user').text
|
74
|
+
end
|
75
|
+
|
76
|
+
return result
|
77
|
+
rescue RestClient::Unauthorized
|
78
|
+
result['status'] = '401 Error - Auth failure (bad username/password).'
|
79
|
+
|
80
|
+
return result
|
81
|
+
rescue RestClient::ResourceNotFound
|
82
|
+
result['status'] = "404 Error - No job found with ID: #{job}."
|
83
|
+
|
84
|
+
return result
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
@@ -0,0 +1,176 @@
|
|
1
|
+
require 'rest-client'
|
2
|
+
require 'nokogiri'
|
3
|
+
require 'junos-space-api/space'
|
4
|
+
|
5
|
+
class JunosSpace::SD::Address
|
6
|
+
@@address_uri = '/api/juniper/sd/address-management/addresses'
|
7
|
+
@@address_headers = {
|
8
|
+
:content_type => "application/vnd.juniper.sd.address-management.address+xml;version=1;charset=UTF-8"
|
9
|
+
}
|
10
|
+
@@ucase = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
|
11
|
+
@@dcase = 'abcdefghijklmnopqrstuvwxyz'
|
12
|
+
|
13
|
+
# addresses
|
14
|
+
#
|
15
|
+
# Returns a Hash of all of the address objects in Space. The name
|
16
|
+
# of the object is the key, and the ID is the value.
|
17
|
+
#
|
18
|
+
def addresses
|
19
|
+
result = {}
|
20
|
+
|
21
|
+
begin
|
22
|
+
res = RestClient.get("#{JunosSpace.base_uri}#{@@address_uri}")
|
23
|
+
doc = Nokogiri::XML::Document.parse(res)
|
24
|
+
|
25
|
+
doc.xpath('//address').each do |address|
|
26
|
+
name = address.xpath('name').text
|
27
|
+
id = address.xpath('id').text
|
28
|
+
|
29
|
+
result[name] = id
|
30
|
+
end
|
31
|
+
|
32
|
+
return result
|
33
|
+
rescue RestClient::Unauthorized
|
34
|
+
result['status'] = '401 Error - Auth failure (bad username/password).'
|
35
|
+
|
36
|
+
return result
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
# address_info(name)
|
41
|
+
#
|
42
|
+
# Searches for address object 'name' and returns a Hash with the address
|
43
|
+
# object(s) name as the key, and the IP address as the value.
|
44
|
+
# If the address object(s) are a group, then the value within
|
45
|
+
# the Hash is an array of the address object names within the group(s).
|
46
|
+
#
|
47
|
+
def address_info(name)
|
48
|
+
result = {}
|
49
|
+
|
50
|
+
begin
|
51
|
+
res = RestClient.get("#{JunosSpace.base_uri}#{@@address_uri}", :params => {:filter => "(global eq '#{name}')"})
|
52
|
+
doc = Nokogiri::XML::Document.parse(res)
|
53
|
+
count = doc.xpath('//addresses/@total').text
|
54
|
+
|
55
|
+
if count == "0"
|
56
|
+
result['status'] = 'No address object(s) found.'
|
57
|
+
else
|
58
|
+
doc.xpath("//address[contains(translate(name, '#{@@ucase}', '#{@@dcase}'), translate('#{name}', '#{@@ucase}', '#{@@dcase}'))]").each do |address|
|
59
|
+
name = address.xpath('name').text
|
60
|
+
type = address.xpath('address-type').text
|
61
|
+
id = address.xpath('id').text
|
62
|
+
|
63
|
+
if type != 'GROUP'
|
64
|
+
address.xpath('//address').each do |info|
|
65
|
+
ip = info.xpath('ip-address').text
|
66
|
+
result[name] = ip
|
67
|
+
end
|
68
|
+
elsif type == 'GROUP'
|
69
|
+
res = RestClient.get("#{JunosSpace.base_uri}#{@@address_uri}/#{id}")
|
70
|
+
doc = Nokogiri::XML::Document.parse(res)
|
71
|
+
|
72
|
+
group_members = []
|
73
|
+
doc.xpath('//member').each do |member|
|
74
|
+
member_name = member.xpath('name').text
|
75
|
+
member_ip = member.xpath('ip-address').text
|
76
|
+
group_members << member_name
|
77
|
+
end
|
78
|
+
result[name] = group_members
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
return result
|
84
|
+
rescue RestClient::Unauthorized
|
85
|
+
result['status'] = '401 Error - Auth failure (bad username/password).'
|
86
|
+
|
87
|
+
return result
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
# add_address(data)
|
92
|
+
#
|
93
|
+
# This method will add a new address object to Space give the information
|
94
|
+
# in 'data'. This information is a Hash with the following structure:
|
95
|
+
#
|
96
|
+
# `name => Name of the object you want to create`,
|
97
|
+
# `type => Either 'address' or 'network'`,
|
98
|
+
# `ip => IP address or subnet/mask`,
|
99
|
+
# `desc => Description (optional)`,
|
100
|
+
# `version => Either 'v4' or 'v6'`
|
101
|
+
#
|
102
|
+
def add_address(data)
|
103
|
+
result = {}
|
104
|
+
type = data['type'] == 'address' ? 'IPADDRESS' : 'NETWORK'
|
105
|
+
version = data['version'] == 'v4' ? 'IPV4' : 'IPV6'
|
106
|
+
if data['desc']
|
107
|
+
desc = data['desc']
|
108
|
+
else
|
109
|
+
desc = ''
|
110
|
+
end
|
111
|
+
|
112
|
+
xml = "<address><name>#{data['name']}</name><address-type>#{type}</address-type>" +
|
113
|
+
"<host-name/><edit-version/><members/><address-version>#{version}</address-version>" +
|
114
|
+
"<definition-type>CUSTOM</definition-type><ip-address>#{data['ip']}</ip-address>" +
|
115
|
+
"<description>#{desc}</description></address>"
|
116
|
+
|
117
|
+
begin
|
118
|
+
res = RestClient.post("#{JunosSpace.base_uri}#{@@address_uri}", xml, @@address_headers)
|
119
|
+
|
120
|
+
if res.code == 200
|
121
|
+
result['status'] = '200 OK - Success'
|
122
|
+
end
|
123
|
+
|
124
|
+
return result
|
125
|
+
rescue RestClient::Unauthorized
|
126
|
+
result['status'] = '401 Error - Auth failure (bad username/password).'
|
127
|
+
|
128
|
+
return result
|
129
|
+
rescue RestClient::InternalServerError
|
130
|
+
result['status'] = '500 Error - Check and see if the device already exists.'
|
131
|
+
|
132
|
+
return result
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
# delete_address(name)
|
137
|
+
#
|
138
|
+
# Deletes the object matching the name 'name'. If more than one address object
|
139
|
+
# is found during the search, then send a warning to refine the search (i.e.
|
140
|
+
# use the exact name if possible).
|
141
|
+
#
|
142
|
+
def delete_address(name)
|
143
|
+
result = {}
|
144
|
+
|
145
|
+
begin
|
146
|
+
res = RestClient.get("#{JunosSpace.base_uri}#{@@address_uri}", :params => {:filter => "(global eq '#{name}')"})
|
147
|
+
doc = Nokogiri::XML::Document.parse(res)
|
148
|
+
headers = {
|
149
|
+
:content_type => 'application/vnd.juniper.sd.address-management.delete-address-response+xml;version=1;q=0.01'
|
150
|
+
}
|
151
|
+
num_results = doc.xpath('//addresses/@total').text
|
152
|
+
|
153
|
+
if num_results == "0"
|
154
|
+
result['status'] = 'Address object does not exist.'
|
155
|
+
elsif num_results.to_i > 1
|
156
|
+
result['status'] = 'More than one object was found. Please refine your search (use the exact name if possible).'
|
157
|
+
else
|
158
|
+
doc.xpath("//address[contains(translate(name, '#{@@ucase}', '#{@@dcase}'), translate('#{name}', '#{@@ucase}', '#{@@dcase}'))]").each do |address|
|
159
|
+
id = address.xpath('id').text
|
160
|
+
|
161
|
+
res = RestClient.delete("#{JunosSpace.base_uri}#{@@address_uri}/#{id}", headers)
|
162
|
+
|
163
|
+
if res == ''
|
164
|
+
result['status'] = '200 OK - Success.'
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
return result
|
170
|
+
rescue RestClient::Unauthorized
|
171
|
+
result['status'] = '401 Error - Auth failure (bad username/password).'
|
172
|
+
|
173
|
+
return result
|
174
|
+
end
|
175
|
+
end
|
176
|
+
end
|
@@ -0,0 +1,114 @@
|
|
1
|
+
require 'rest-client'
|
2
|
+
require 'nokogiri'
|
3
|
+
require 'junos-space-api/space'
|
4
|
+
|
5
|
+
class JunosSpace::SD::Device
|
6
|
+
@@device_uri = '/api/juniper/sd/device-management/devices'
|
7
|
+
|
8
|
+
# devices
|
9
|
+
#
|
10
|
+
# Returns a Hash of all of the device objects in Space. The name
|
11
|
+
# of the device is the key, and the ID is the value.
|
12
|
+
#
|
13
|
+
def devices
|
14
|
+
result = {}
|
15
|
+
|
16
|
+
begin
|
17
|
+
res = RestClient.get("#{JunosSpace.base_uri}#{@@device_uri}")
|
18
|
+
doc = Nokogiri::XML::Document.parse(res)
|
19
|
+
|
20
|
+
doc.xpath('//device').each do |device|
|
21
|
+
name = device.xpath('name').text
|
22
|
+
id = device.xpath('id').text
|
23
|
+
|
24
|
+
result[name] = id
|
25
|
+
end
|
26
|
+
|
27
|
+
return result
|
28
|
+
rescue RestClient::Unauthorized
|
29
|
+
result['status'] = '401 Error - Auth failure (bad username/password).'
|
30
|
+
|
31
|
+
return result
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
# device_info(name)
|
36
|
+
#
|
37
|
+
# Returns a Hash of resultrmation about the given device 'name'. For zones,
|
38
|
+
# it returns Hash where the zone name is the key, and an array of interfaces
|
39
|
+
# that are in said zone as the value.
|
40
|
+
#
|
41
|
+
# For interfaces, it returns a Hash where the interface name is the key, and
|
42
|
+
# the IP address of that interface is the value.
|
43
|
+
#
|
44
|
+
def device_info(name)
|
45
|
+
result = {}
|
46
|
+
devices = self.devices
|
47
|
+
|
48
|
+
begin
|
49
|
+
res = RestClient.get("#{JunosSpace.base_uri}#{@@device_uri}/#{devices[name]}")
|
50
|
+
doc = Nokogiri::XML::Document.parse(res)
|
51
|
+
|
52
|
+
if !devices[name]
|
53
|
+
result['status'] = 'No device(s) found.'
|
54
|
+
else
|
55
|
+
doc.xpath('//device').each do |device|
|
56
|
+
result["management-status"] = device.xpath('management-status').text,
|
57
|
+
result["name"] = device.xpath('name').text,
|
58
|
+
result["platform"] = device.xpath('platform').text,
|
59
|
+
result["ip"] = device.xpath('device-ip').text,
|
60
|
+
result["config-status"] = device.xpath('configuration-status').text,
|
61
|
+
result["connection-status"] = device.xpath('connection-status').text,
|
62
|
+
result["family"] = device.xpath('device-family').text,
|
63
|
+
result["version"] = device.xpath('software-release').text,
|
64
|
+
result["id"] = device.xpath('id').text
|
65
|
+
|
66
|
+
zone_uri = device.xpath('Zone/@href').text
|
67
|
+
int_uri = device.xpath('Interfaces/@href').text
|
68
|
+
|
69
|
+
zone_res = RestClient.get("#{JunosSpace.base_uri}#{zone_uri}")
|
70
|
+
zone_doc = Nokogiri::XML::Document.parse(zone_res)
|
71
|
+
int_res = RestClient.get("#{JunosSpace.base_uri}#{int_uri}")
|
72
|
+
int_doc = Nokogiri::XML::Document.parse(int_res)
|
73
|
+
|
74
|
+
zones = []
|
75
|
+
zone_doc.xpath('//zone').each do |zone|
|
76
|
+
zone_ints = []
|
77
|
+
zone_result = {}
|
78
|
+
name = zone.xpath('name').text
|
79
|
+
|
80
|
+
zone.xpath('./interfaces').each do |int|
|
81
|
+
int.xpath('./interface').each do |interface|
|
82
|
+
zone_ints << interface.text
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
zone_result[name] = zone_ints
|
87
|
+
zones << zone_result
|
88
|
+
end
|
89
|
+
|
90
|
+
result["zones"] = zones
|
91
|
+
|
92
|
+
interfaces = []
|
93
|
+
int_doc.xpath('//interface').each do |int|
|
94
|
+
int_result = {}
|
95
|
+
name = int.xpath('name').text
|
96
|
+
ip = int.xpath('ip-addr').text
|
97
|
+
mask = int.xpath('ip-netmask').text
|
98
|
+
int_result[name] = "#{ip}/#{mask}"
|
99
|
+
|
100
|
+
interfaces << int_result
|
101
|
+
end
|
102
|
+
|
103
|
+
result["interfaces"] = interfaces
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
return result
|
108
|
+
rescue RestClient::Unauthorized
|
109
|
+
result['status'] = '401 Error - Auth failure (bad username/password).'
|
110
|
+
|
111
|
+
return result
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
@@ -0,0 +1,175 @@
|
|
1
|
+
require 'rest-client'
|
2
|
+
require 'nokogiri'
|
3
|
+
require 'junos-space-api/space'
|
4
|
+
|
5
|
+
class JunosSpace::SD::Service
|
6
|
+
@@service_uri = '/api/juniper/sd/service-management/services'
|
7
|
+
@@service_headers = {
|
8
|
+
:content_type => "application/vnd.juniper.sd.service-management.service+xml;version=1;charset=UTF-8"
|
9
|
+
}
|
10
|
+
@@ucase = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
|
11
|
+
@@dcase = 'abcdefghijklmnopqrstuvwxyz'
|
12
|
+
|
13
|
+
# services
|
14
|
+
#
|
15
|
+
# Returns a Hash of all of the individual service objects in Space.
|
16
|
+
# The name of the service is the key, and the ID is the value.
|
17
|
+
#
|
18
|
+
def services
|
19
|
+
result = {}
|
20
|
+
|
21
|
+
begin
|
22
|
+
res = RestClient.get("#{JunosSpace.base_uri}#{@@service_uri}")
|
23
|
+
doc = Nokogiri::XML::Document.parse(res)
|
24
|
+
|
25
|
+
doc.xpath('//service').each do |service|
|
26
|
+
name = service.xpath('name').text
|
27
|
+
id = service.xpath('id').text
|
28
|
+
|
29
|
+
result[name] = id
|
30
|
+
end
|
31
|
+
|
32
|
+
return result
|
33
|
+
rescue RestClient::Unauthorized
|
34
|
+
result['status'] = '401 Error - Auth failure (bad username/password).'
|
35
|
+
|
36
|
+
return result
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
# service_info(name)
|
41
|
+
#
|
42
|
+
# Searches for the service 'name' and returns a Hash with the service
|
43
|
+
# object(s) name as the key, and the ID as the value.
|
44
|
+
# If the service object(s) are a group, then the value within
|
45
|
+
# the Hash is an array of the service object names within the group(s).
|
46
|
+
#
|
47
|
+
def service_info(name)
|
48
|
+
result = {}
|
49
|
+
|
50
|
+
begin
|
51
|
+
res = RestClient.get("#{JunosSpace.base_uri}#{@@service_uri}", :params => {:filter => "(global eq '#{name}')"})
|
52
|
+
doc = Nokogiri::XML::Document.parse(res)
|
53
|
+
count = doc.xpath('//services/@total').text
|
54
|
+
|
55
|
+
if count == "0"
|
56
|
+
result['status'] = 'No service object(s) found.'
|
57
|
+
else
|
58
|
+
doc.xpath("//service[contains(translate(name, '#{@@ucase}', '#{@@dcase}'), translate('#{name}', '#{@@ucase}', '#{@@dcase}'))]").each do |service|
|
59
|
+
group = service.xpath('is-group').text
|
60
|
+
name = service.xpath('name').text
|
61
|
+
id = service.xpath('id').text
|
62
|
+
|
63
|
+
if group == 'false'
|
64
|
+
res = RestClient.get("#{JunosSpace.base_uri}#{@@service_uri}/#{id}")
|
65
|
+
doc = Nokogiri::XML::Document.parse(res)
|
66
|
+
|
67
|
+
doc.xpath('//protocol').each do |info|
|
68
|
+
dst_port = info.xpath('dst-port').text
|
69
|
+
result[name] = dst_port
|
70
|
+
end
|
71
|
+
elsif group == 'true'
|
72
|
+
res = RestClient.get("#{JunosSpace.base_uri}#{@@service_uri}/#{id}")
|
73
|
+
doc = Nokogiri::XML::Document.parse(res)
|
74
|
+
|
75
|
+
group_members = []
|
76
|
+
doc.xpath('//member').each do |member|
|
77
|
+
member_name = member.xpath('name').text
|
78
|
+
group_members << member_name
|
79
|
+
end
|
80
|
+
result[name] = group_members
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
return result
|
86
|
+
rescue RestClient::Unauthorized
|
87
|
+
result['status'] = '401 Error - Auth failure (bad username/password).'
|
88
|
+
|
89
|
+
return result
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
# add_service(data)
|
94
|
+
#
|
95
|
+
# This method will add a new service object to Space give the information
|
96
|
+
# in 'data'. This information is a Hash table, with the following structure:
|
97
|
+
#
|
98
|
+
# `name => `Name of the object you want to create`
|
99
|
+
# `port => Port number`
|
100
|
+
# `desc => Description (optional)`
|
101
|
+
#
|
102
|
+
def add_service(data)
|
103
|
+
result = {}
|
104
|
+
|
105
|
+
if data['desc']
|
106
|
+
desc = data['desc']
|
107
|
+
else
|
108
|
+
desc = ''
|
109
|
+
end
|
110
|
+
|
111
|
+
xml = "<service><name>#{data['name']}</name><is-group>false</is-group><edit-version/>" +
|
112
|
+
"<id/><created-by-user-name/><members/><protocols><protocol><description/>" +
|
113
|
+
"<sunrpc-protocol-type>6</sunrpc-protocol-type><msrpc-protocol-type>6</msrpc-protocol-type>" +
|
114
|
+
"<protocol-number>6</protocol-number><name>#{data['name']}</name><dst-port>#{data['port']}</dst-port>" +
|
115
|
+
"<disable-timeout>false</disable-timeout><protocol-type>0</protocol-type><icmp-code>0</icmp-code>" +
|
116
|
+
"<icmp-type>0</icmp-type><rpc-program-number>0</rpc-program-number>" +
|
117
|
+
"</protocol></protocols><description>#{desc}</description></service>"
|
118
|
+
|
119
|
+
begin
|
120
|
+
res = RestClient.post("#{JunosSpace.base_uri}#{@@service_uri}", xml, @@service_headers)
|
121
|
+
|
122
|
+
if res.code == 200
|
123
|
+
result['status'] = '200 OK - Success'
|
124
|
+
end
|
125
|
+
|
126
|
+
return result
|
127
|
+
rescue RestClient::Unauthorized
|
128
|
+
result['status'] = '401 Error - Auth failure (bad username/password).'
|
129
|
+
|
130
|
+
return result
|
131
|
+
rescue RestClient::InternalServerError
|
132
|
+
result['status'] = '500 Error - Check and see if the device already exists.'
|
133
|
+
|
134
|
+
return result
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
# delete_service(name)
|
139
|
+
#
|
140
|
+
# Deletes the object matching the name 'name'. If more than one service object
|
141
|
+
# is found during the search, then send a warning to refine the search (i.e.
|
142
|
+
# use the exact name if possible).
|
143
|
+
#
|
144
|
+
def delete_service(name)
|
145
|
+
result = {}
|
146
|
+
|
147
|
+
begin
|
148
|
+
res = RestClient.get("#{JunosSpace.base_uri}#{@@service_uri}", :params => {:filter => "(global eq '#{name}')"})
|
149
|
+
doc = Nokogiri::XML::Document.parse(res)
|
150
|
+
num_results = doc.xpath('//services/@total').text
|
151
|
+
|
152
|
+
if num_results == "0"
|
153
|
+
result['status'] = 'Service object does not exist.'
|
154
|
+
elsif num_results.to_i > 1
|
155
|
+
result['status'] = 'More than one object was found. Please refine your search (use the exact name if possible).'
|
156
|
+
else
|
157
|
+
doc.xpath("//service[contains(translate(name, '#{@@ucase}', '#{@@dcase}'), translate('#{name}', '#{@@ucase}', '#{@@dcase}'))]").each do |service|
|
158
|
+
id = service.xpath('id').text
|
159
|
+
|
160
|
+
res = RestClient.delete("#{JunosSpace.base_uri}#{@@service_uri}/#{id}", @@service_headers)
|
161
|
+
|
162
|
+
if res == ''
|
163
|
+
result['status'] = '200 OK - Success.'
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
return result
|
169
|
+
rescue RestClient::Unauthorized
|
170
|
+
result['status'] = '401 Error - Auth failure (bad username/password).'
|
171
|
+
|
172
|
+
return result
|
173
|
+
end
|
174
|
+
end
|
175
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module JunosSpace
|
2
|
+
# JunosSpace.open
|
3
|
+
#
|
4
|
+
# Initiates the connection to the Junos Space server.
|
5
|
+
#
|
6
|
+
def self.open(user, pass, server)
|
7
|
+
@conn_str = "https://#{user}:#{pass}@#{server}"
|
8
|
+
end
|
9
|
+
|
10
|
+
# JunosSpace.base_uri
|
11
|
+
#
|
12
|
+
# Returns the base URI for the API to use in our classes
|
13
|
+
#
|
14
|
+
def self.base_uri
|
15
|
+
@conn_str
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
module JunosSpace::Platform; end
|
20
|
+
module JunosSpace::SD; end
|
metadata
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: junos-space-api
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.2.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Scott Ware
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-07-09 00:00:00.000000000 Z
|
13
|
+
dependencies: []
|
14
|
+
description: This gem is used to interact with Juniper Networks Junos Space management
|
15
|
+
platform using the REST API.
|
16
|
+
email: scottdware@gmail.com
|
17
|
+
executables: []
|
18
|
+
extensions: []
|
19
|
+
extra_rdoc_files: []
|
20
|
+
files:
|
21
|
+
- junos-space-api.gemspec
|
22
|
+
- LICENSE
|
23
|
+
- README.md
|
24
|
+
- lib/junos-space-api/platform/device.rb
|
25
|
+
- lib/junos-space-api/platform/job.rb
|
26
|
+
- lib/junos-space-api/platform.rb
|
27
|
+
- lib/junos-space-api/sd/address.rb
|
28
|
+
- lib/junos-space-api/sd/device.rb
|
29
|
+
- lib/junos-space-api/sd/service.rb
|
30
|
+
- lib/junos-space-api/sd.rb
|
31
|
+
- lib/junos-space-api/space.rb
|
32
|
+
- examples/addresses.rb
|
33
|
+
- examples/add_device.rb
|
34
|
+
- examples/jobs.rb
|
35
|
+
- examples/sec_device.rb
|
36
|
+
- examples/services.rb
|
37
|
+
homepage: https://github.com/scottdware/junos-ruby-space-api
|
38
|
+
licenses:
|
39
|
+
- MIT
|
40
|
+
post_install_message:
|
41
|
+
rdoc_options: []
|
42
|
+
require_paths:
|
43
|
+
- lib
|
44
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
45
|
+
none: false
|
46
|
+
requirements:
|
47
|
+
- - ! '>='
|
48
|
+
- !ruby/object:Gem::Version
|
49
|
+
version: '0'
|
50
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
51
|
+
none: false
|
52
|
+
requirements:
|
53
|
+
- - ! '>='
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
version: '0'
|
56
|
+
requirements: []
|
57
|
+
rubyforge_project:
|
58
|
+
rubygems_version: 1.8.24
|
59
|
+
signing_key:
|
60
|
+
specification_version: 3
|
61
|
+
summary: Interact with the Junos Space REST API.
|
62
|
+
test_files: []
|