junos-space-api 0.2.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/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: []
|