smart_proxy_dhcp_bluecat 0.1.5 → 0.1.6
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.
- checksums.yaml +4 -4
- data/bundler.d/dhcp_bluecat.rb +1 -1
- data/lib/smart_proxy_dhcp_bluecat/bluecat_api.rb +438 -386
- data/lib/smart_proxy_dhcp_bluecat/dhcp_bluecat_main.rb +45 -40
- data/lib/smart_proxy_dhcp_bluecat/dhcp_bluecat_plugin.rb +3 -2
- data/lib/smart_proxy_dhcp_bluecat/dhcp_bluecat_version.rb +7 -7
- data/lib/smart_proxy_dhcp_bluecat/module_loader.rb +1 -1
- data/lib/smart_proxy_dhcp_bluecat/plugin_configuration.rb +24 -24
- data/lib/smart_proxy_dhcp_bluecat/settings_validator.rb +21 -2
- data/lib/smart_proxy_dhcp_bluecat.rb +5 -5
- metadata +6 -20
@@ -1,386 +1,438 @@
|
|
1
|
-
require
|
2
|
-
require
|
3
|
-
require
|
4
|
-
|
5
|
-
module Proxy
|
6
|
-
module DHCP
|
7
|
-
module BlueCat
|
8
|
-
##
|
9
|
-
# This Class handles all commuincation to the bluecat address manager
|
10
|
-
class BlueCatAPI
|
11
|
-
include ::Proxy::Log
|
12
|
-
|
13
|
-
# connection mode to the address manager. http or https
|
14
|
-
attr_reader :scheme
|
15
|
-
|
16
|
-
# validate ssl connection. true or false
|
17
|
-
attr_reader :verify
|
18
|
-
|
19
|
-
# fqdn or ip of your bluecat address manager
|
20
|
-
attr_reader :host
|
21
|
-
|
22
|
-
# id of the parent_block that holds the subnets that you want to use
|
23
|
-
attr_reader :parent_block
|
24
|
-
|
25
|
-
# name of your dns view
|
26
|
-
attr_reader :view_name
|
27
|
-
|
28
|
-
# Name of your Bluecat configuration
|
29
|
-
attr_reader :config_name
|
30
|
-
|
31
|
-
# id of your Bluecat configuration
|
32
|
-
attr_reader :config_id
|
33
|
-
|
34
|
-
# id of the server that holds your dhcp
|
35
|
-
attr_reader :server_id
|
36
|
-
|
37
|
-
# credentials of your api user
|
38
|
-
attr_reader :username
|
39
|
-
|
40
|
-
# credentials of your api user
|
41
|
-
attr_reader :password
|
42
|
-
|
43
|
-
class << self
|
44
|
-
# contains the bluecat api token
|
45
|
-
attr_accessor :token
|
46
|
-
end
|
47
|
-
|
48
|
-
def initialize(scheme, verify, host, parent_block, view_name, config_name, config_id, server_id, username, password)
|
49
|
-
@scheme = scheme
|
50
|
-
@verify = verify
|
51
|
-
@host = host
|
52
|
-
@parent_block = parent_block
|
53
|
-
@view_name = view_name
|
54
|
-
@config_name = config_name
|
55
|
-
@config_id = config_id
|
56
|
-
@server_id = server_id
|
57
|
-
@username = username
|
58
|
-
@password = password
|
59
|
-
end
|
60
|
-
|
61
|
-
# login to bam, parse the session token
|
62
|
-
def rest_login
|
63
|
-
logger.debug(
|
64
|
-
response = HTTParty.get(format(
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
response
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
end
|
1
|
+
require "httparty"
|
2
|
+
require "ipaddress"
|
3
|
+
require "json"
|
4
|
+
|
5
|
+
module Proxy
|
6
|
+
module DHCP
|
7
|
+
module BlueCat
|
8
|
+
##
|
9
|
+
# This Class handles all commuincation to the bluecat address manager
|
10
|
+
class BlueCatAPI
|
11
|
+
include ::Proxy::Log
|
12
|
+
|
13
|
+
# connection mode to the address manager. http or https
|
14
|
+
attr_reader :scheme
|
15
|
+
|
16
|
+
# validate ssl connection. true or false
|
17
|
+
attr_reader :verify
|
18
|
+
|
19
|
+
# fqdn or ip of your bluecat address manager
|
20
|
+
attr_reader :host
|
21
|
+
|
22
|
+
# id of the parent_block that holds the subnets that you want to use
|
23
|
+
attr_reader :parent_block
|
24
|
+
|
25
|
+
# name of your dns view
|
26
|
+
attr_reader :view_name
|
27
|
+
|
28
|
+
# Name of your Bluecat configuration
|
29
|
+
attr_reader :config_name
|
30
|
+
|
31
|
+
# id of your Bluecat configuration
|
32
|
+
attr_reader :config_id
|
33
|
+
|
34
|
+
# id of the server that holds your dhcp
|
35
|
+
attr_reader :server_id
|
36
|
+
|
37
|
+
# credentials of your api user
|
38
|
+
attr_reader :username
|
39
|
+
|
40
|
+
# credentials of your api user
|
41
|
+
attr_reader :password
|
42
|
+
|
43
|
+
class << self
|
44
|
+
# contains the bluecat api token
|
45
|
+
attr_accessor :token
|
46
|
+
end
|
47
|
+
|
48
|
+
def initialize(scheme, verify, host, parent_block, view_name, config_name, config_id, server_id, username, password)
|
49
|
+
@scheme = scheme
|
50
|
+
@verify = verify
|
51
|
+
@host = host
|
52
|
+
@parent_block = parent_block
|
53
|
+
@view_name = view_name
|
54
|
+
@config_name = config_name
|
55
|
+
@config_id = config_id
|
56
|
+
@server_id = server_id
|
57
|
+
@username = username
|
58
|
+
@password = password
|
59
|
+
end
|
60
|
+
|
61
|
+
# login to bam, parse the session token
|
62
|
+
def rest_login
|
63
|
+
logger.debug("BAM Login #{@scheme} #{@host} ")
|
64
|
+
response = HTTParty.get(format("%s://%s/Services/REST/v1/login?username=%s&password=%s",
|
65
|
+
@scheme,
|
66
|
+
@host,
|
67
|
+
@username,
|
68
|
+
@password),
|
69
|
+
headers: { "Content-Type" => "text/plain" },
|
70
|
+
verify => @verify)
|
71
|
+
logger.error("BAM Login Failed. HTTP#{response.code} #{response.body}") if response.code != 200
|
72
|
+
body = response.body.to_s
|
73
|
+
token = body.match(/BAMAuthToken:\s+(\S+)/).captures
|
74
|
+
|
75
|
+
logger.debug("BAM Login Body #{response.body}")
|
76
|
+
logger.debug("BAM Login Token #{token[0]}")
|
77
|
+
self.class.token = token[0].to_s
|
78
|
+
end
|
79
|
+
|
80
|
+
# logout from bam
|
81
|
+
def rest_logout
|
82
|
+
logger.debug("BAM Logout ")
|
83
|
+
response = HTTParty.get(format("%s://%s/Services/REST/v1/logout", @scheme, @host),
|
84
|
+
headers: { "Authorization" => "BAMAuthToken: #{self.class.token}",
|
85
|
+
"Content-Type" => "application/json" },
|
86
|
+
verify: @verify)
|
87
|
+
logger.error("BAM Logout Failed. HTTP#{response.code} #{response.body}") if response.code != 200
|
88
|
+
end
|
89
|
+
|
90
|
+
# wrapper function to for rest get requests
|
91
|
+
def rest_get(endpoint, querystring)
|
92
|
+
rest_login if self.class.token.nil?
|
93
|
+
|
94
|
+
logger.debug("BAM GET #{endpoint}?#{querystring}")
|
95
|
+
|
96
|
+
response = HTTParty.get(format("%s://%s/Services/REST/v1/%s?%s", @scheme, @host, endpoint, querystring),
|
97
|
+
headers: { "Authorization" => "BAMAuthToken: #{self.class.token}",
|
98
|
+
"Content-Type" => "application/json" },
|
99
|
+
verify: @verify)
|
100
|
+
# Session propably expired, refresh it and do the request again
|
101
|
+
if response.code == 401
|
102
|
+
rest_login
|
103
|
+
response = HTTParty.get(format("%s://%s/Services/REST/v1/%s?%s", @scheme, @host, endpoint, querystring),
|
104
|
+
headers: { "Authorization" => "BAMAuthToken: #{self.class.token}",
|
105
|
+
"Content-Type" => "application/json" },
|
106
|
+
verify: @verify)
|
107
|
+
end
|
108
|
+
|
109
|
+
return response.body if response.code == 200
|
110
|
+
|
111
|
+
logger.error("BAM GET Failed. HTTP#{response.code} #{response.body}")
|
112
|
+
end
|
113
|
+
|
114
|
+
# wrapper function to for rest post requests
|
115
|
+
def rest_post(endpoint, querystring)
|
116
|
+
logger.debug("BAM POST #{endpoint}?#{querystring}")
|
117
|
+
response = HTTParty.post(format("%s://%s/Services/REST/v1/%s?%s", @scheme, @host, endpoint, querystring),
|
118
|
+
headers: { "Authorization" => "BAMAuthToken: #{self.class.token}",
|
119
|
+
"Content-Type" => "application/json" },
|
120
|
+
verify: @verify)
|
121
|
+
# Session propably expired, refresh it and do the request again
|
122
|
+
if response.code == 401
|
123
|
+
rest_login
|
124
|
+
response = HTTParty.post(format("%s://%s/Services/REST/v1/%s?%s", @scheme, @host, endpoint, querystring),
|
125
|
+
headers: { "Authorization" => "BAMAuthToken: #{self.class.token}",
|
126
|
+
"Content-Type" => "application/json" },
|
127
|
+
verify: @verify)
|
128
|
+
end
|
129
|
+
return response.body if response.code == 200
|
130
|
+
|
131
|
+
logger.error("BAM POST Failed. HTTP#{response.code} #{response.body}")
|
132
|
+
end
|
133
|
+
|
134
|
+
# wrapper function to for rest put requests
|
135
|
+
def rest_put(endpoint, querystring)
|
136
|
+
logger.debug("BAM PUT #{endpoint}?#{querystring}")
|
137
|
+
response = HTTParty.put(format("%s://%s/Services/REST/v1/%s?%s", @scheme, @host, endpoint, querystring),
|
138
|
+
headers: { "Authorization" => "BAMAuthToken: #{self.class.token}",
|
139
|
+
"Content-Type" => "application/json" },
|
140
|
+
verify: @verify)
|
141
|
+
# Session propably expired, refresh it and do the request again
|
142
|
+
if response.code == 401
|
143
|
+
rest_login
|
144
|
+
response = HTTParty.put(format("%s://%s/Services/REST/v1/%s?%s", @scheme, @host, endpoint, querystring),
|
145
|
+
headers: { "Authorization" => "BAMAuthToken: #{self.class.token}",
|
146
|
+
"Content-Type" => "application/json" },
|
147
|
+
verify: @verify)
|
148
|
+
end
|
149
|
+
return response.body if response.code == 200
|
150
|
+
|
151
|
+
logger.error("BAM PUT Failed. HTTP#{response.code} #{response.body}")
|
152
|
+
end
|
153
|
+
|
154
|
+
# wrapper function to for rest delete requests
|
155
|
+
def rest_delete(endpoint, querystring)
|
156
|
+
logger.debug("BAM DELETE #{endpoint}?#{querystring}")
|
157
|
+
response = HTTParty.delete(format("%s://%s/Services/REST/v1/%s?%s", @scheme, @host, endpoint, querystring),
|
158
|
+
headers: { "Authorization" => "BAMAuthToken: #{self.class.token}",
|
159
|
+
"Content-Type" => "application/json" },
|
160
|
+
verify: @verify)
|
161
|
+
|
162
|
+
# Session propably expired, refresh it and do the request again
|
163
|
+
if response.code == 401
|
164
|
+
rest_login
|
165
|
+
response = HTTParty.delete(format("%s://%s/Services/REST/v1/%s?%s", @scheme, @host, endpoint, querystring),
|
166
|
+
headers: { "Authorization" => "BAMAuthToken: #{self.class.token}",
|
167
|
+
"Content-Type" => "application/json" },
|
168
|
+
verify: @verify)
|
169
|
+
end
|
170
|
+
return response.body if response.code == 200
|
171
|
+
|
172
|
+
logger.error("BAM DELETE Failed. HTTP#{response.code} #{response.body}")
|
173
|
+
end
|
174
|
+
|
175
|
+
# helper function to get the object id of a ip by an ip address
|
176
|
+
def get_addressid_by_ip(ip)
|
177
|
+
json = rest_get("getIP4Address", "containerId=#{@config_id}&address=#{ip}")
|
178
|
+
result = JSON.parse(json)
|
179
|
+
return nil if result.empty?
|
180
|
+
|
181
|
+
result["id"].to_s
|
182
|
+
end
|
183
|
+
|
184
|
+
# helper function to get the object id of a subnet by an ip address
|
185
|
+
def get_networkid_by_ip(ip)
|
186
|
+
logger.debug("BAM get_networkid_by_ip #{ip}")
|
187
|
+
querystring = "containerId=#{@config_id}&type=IP4Network&address=#{ip}"
|
188
|
+
json = rest_get("getIPRangedByIP", querystring)
|
189
|
+
result = JSON.parse(json)
|
190
|
+
return nil if result.empty?
|
191
|
+
|
192
|
+
result["id"].to_s
|
193
|
+
end
|
194
|
+
|
195
|
+
# helper function to get the whole subnet informarions by an ip address
|
196
|
+
def get_network_by_ip(ip)
|
197
|
+
logger.debug("BAM get_network_by_ip #{ip}")
|
198
|
+
querystring = "containerId=#{@config_id}&type=IP4Network&address=#{ip}"
|
199
|
+
json = rest_get("getIPRangedByIP", querystring)
|
200
|
+
result = JSON.parse(json)
|
201
|
+
properties = parse_properties(result["properties"])
|
202
|
+
properties["CIDR"].to_s
|
203
|
+
end
|
204
|
+
|
205
|
+
# helper function to parse the properties scheme of bluecat into a hash
|
206
|
+
#
|
207
|
+
# properies: a string that contains properties for the object in attribute=value format,
|
208
|
+
# with each separated by a | (pipe) character.
|
209
|
+
# For example, a host record object may have a properties field such as ttl=123|comments=my comment|.
|
210
|
+
def parse_properties(properties)
|
211
|
+
properties = properties.split("|")
|
212
|
+
h = {}
|
213
|
+
properties.each do |property|
|
214
|
+
h[property.split("=").first.to_s] = property.split("=").last.to_s
|
215
|
+
end
|
216
|
+
h
|
217
|
+
end
|
218
|
+
|
219
|
+
# public
|
220
|
+
# wrapper function to add the dhcp reservation and dns records
|
221
|
+
def add_host(options)
|
222
|
+
# add the ip and hostname and mac as static
|
223
|
+
rest_post("addDeviceInstance",
|
224
|
+
"configName=#{@config_name} \
|
225
|
+
&ipAddressMode=PASS_VALUE \
|
226
|
+
&ipEntity=#{options["ip"]} \
|
227
|
+
&viewName=#{@view_name} \
|
228
|
+
&zoneName=#{options["hostname"].split(".", 2).last} \
|
229
|
+
&deviceName=#{options["hostname"]} \
|
230
|
+
&recordName=#{options["hostname"]} \
|
231
|
+
&macAddressMode=PASS_VALUE \
|
232
|
+
&macEntity=#{options["mac"]} \
|
233
|
+
&options=AllowDuplicateHosts=true%7C")
|
234
|
+
|
235
|
+
address_id = get_addressid_by_ip(options["ip"])
|
236
|
+
|
237
|
+
# update the state of the ip from static to dhcp reserved
|
238
|
+
rest_put("changeStateIP4Address",
|
239
|
+
"addressId=#{address_id} \
|
240
|
+
&targetState=MAKE_DHCP_RESERVED \
|
241
|
+
&macAddress=#{options["mac"]}")
|
242
|
+
|
243
|
+
unless options["nextServer"].nil? || options["filename"].nil?
|
244
|
+
rest_post("addDHCPClientDeploymentOption",
|
245
|
+
"entityId=#{address_id}&name=tftp-server-name&value=#{options["nextServer"]}")
|
246
|
+
rest_post("addDHCPClientDeploymentOption",
|
247
|
+
"entityId=#{address_id}&name=boot-file-name&value=#{options["filename"]}")
|
248
|
+
end
|
249
|
+
|
250
|
+
# deploy the config
|
251
|
+
rest_post("deployServerConfig", "serverId=#{@server_id}&properties=services=DHCP")
|
252
|
+
# lets wait a little bit for the complete dhcp deploy
|
253
|
+
sleep 3
|
254
|
+
rest_post("deployServerConfig", "serverId=#{@server_id}&properties=services=DNS")
|
255
|
+
nil
|
256
|
+
end
|
257
|
+
|
258
|
+
# public
|
259
|
+
# wrapper function to remove a ip record and depending dns records
|
260
|
+
def remove_host(ip)
|
261
|
+
ipid = get_addressid_by_ip(ip)
|
262
|
+
json = rest_get("getLinkedEntities", "entityId=#{ipid}&type=HostRecord&start=0&count=2")
|
263
|
+
results = JSON.parse(json)
|
264
|
+
|
265
|
+
results.map do |result|
|
266
|
+
rest_delete("delete", "objectId=#{result["id"]}")
|
267
|
+
end
|
268
|
+
rest_delete("delete", "objectId=#{ipid}")
|
269
|
+
|
270
|
+
rest_post("deployServerConfig", "serverId=#{@server_id}&properties=services=DHCP,DNS")
|
271
|
+
end
|
272
|
+
|
273
|
+
# public
|
274
|
+
# fetches the next free address in a subnet
|
275
|
+
# +end_ip not implemented+
|
276
|
+
def next_ip(netadress, start_ip, _end_ip)
|
277
|
+
networkid = get_networkid_by_ip(netadress)
|
278
|
+
|
279
|
+
start_ip = IPAddress.parse(netadress).first if start_ip.to_s.empty?
|
280
|
+
|
281
|
+
properties = "offset=#{start_ip}%7CexcludeDHCPRange=false"
|
282
|
+
result = rest_get("getNextIP4Address", "parentId=#{networkid}&properties=#{properties}")
|
283
|
+
return if result.empty?
|
284
|
+
|
285
|
+
result.tr('"', "")
|
286
|
+
end
|
287
|
+
|
288
|
+
# public
|
289
|
+
# fetches all subnets under the parent_block
|
290
|
+
def subnets
|
291
|
+
json = rest_get("getEntities", "parentId=#{@parent_block}&type=IP4Network&start=0&count=10000")
|
292
|
+
results = JSON.parse(json)
|
293
|
+
subnets = results.map do |result|
|
294
|
+
properties = parse_properties(result["properties"])
|
295
|
+
net = IPAddress.parse(properties["CIDR"])
|
296
|
+
opts = { routers: [properties["gateway"]] }
|
297
|
+
|
298
|
+
if properties["gateway"].nil?
|
299
|
+
logger.error("subnet issue: #{properties["CIDR"]} skipped, due missing gateway in bluecat")
|
300
|
+
next
|
301
|
+
end
|
302
|
+
|
303
|
+
::Proxy::DHCP::Subnet.new(net.address, net.netmask, opts)
|
304
|
+
end
|
305
|
+
subnets.compact
|
306
|
+
end
|
307
|
+
|
308
|
+
# public
|
309
|
+
# fetches a subnet by its network address
|
310
|
+
def find_mysubnet(subnet_address)
|
311
|
+
net = IPAddress.parse(get_network_by_ip(subnet_address))
|
312
|
+
::Proxy::DHCP::Subnet.new(net.address, net.netmask)
|
313
|
+
end
|
314
|
+
|
315
|
+
# public
|
316
|
+
# fetches all dhcp reservations in a subnet
|
317
|
+
def hosts(network_address)
|
318
|
+
netid = get_networkid_by_ip(network_address)
|
319
|
+
net = IPAddress.parse(get_network_by_ip(network_address))
|
320
|
+
subnet = ::Proxy::DHCP::Subnet.new(net.address, net.netmask)
|
321
|
+
|
322
|
+
json = rest_get("getNetworkLinkedProperties", "networkId=#{netid}")
|
323
|
+
results = JSON.parse(json)
|
324
|
+
|
325
|
+
hosts = results.map do |result|
|
326
|
+
properties = parse_properties(result["properties"])
|
327
|
+
|
328
|
+
## Static Addresses and Gateway are not needed here
|
329
|
+
## But lets keep the logic to identify them
|
330
|
+
# if properties.length() >= 4
|
331
|
+
# if properties["state"] == "Gateway" or properties["state"] == "Static"
|
332
|
+
# address = properties[0].split("=").last()
|
333
|
+
# macAddress = "00:00:00:00:00:00"
|
334
|
+
# hosttag = properties[3].split("=").last().split(":")
|
335
|
+
# name = hosttag[1] + "." + hosttag[3]
|
336
|
+
# opts = {:hostname => name}
|
337
|
+
# ::Proxy::DHCP::Reservation.new(name, address, macAddress, subnet, opts)
|
338
|
+
# end
|
339
|
+
# end
|
340
|
+
next unless properties.length >= 5
|
341
|
+
next unless properties["state"] == "DHCP Reserved"
|
342
|
+
|
343
|
+
hosttag = properties["host"].split(":")
|
344
|
+
name = "#{hosttag[1]}.#{hosttag[3]}"
|
345
|
+
opts = { hostname: name }
|
346
|
+
::Proxy::DHCP::Reservation.new(name, properties["address"], properties["macAddress"].tr("-", ":"), subnet, opts)
|
347
|
+
end
|
348
|
+
hosts.compact
|
349
|
+
end
|
350
|
+
|
351
|
+
# public
|
352
|
+
# fetches a host by its ip
|
353
|
+
def hosts_by_ip(ip)
|
354
|
+
hosts = []
|
355
|
+
net = IPAddress.parse(get_network_by_ip(ip))
|
356
|
+
subnet = ::Proxy::DHCP::Subnet.new(net.address, net.netmask)
|
357
|
+
ipid = get_addressid_by_ip(ip)
|
358
|
+
return nil if ipid.to_s == "0"
|
359
|
+
|
360
|
+
json = rest_get("getLinkedEntities", "entityId=#{ipid}&type=HostRecord&start=0&count=2")
|
361
|
+
results = JSON.parse(json)
|
362
|
+
|
363
|
+
if results.empty? || (results == "Link request is not supported")
|
364
|
+
# no host record on ip, fetch mac only
|
365
|
+
json2 = rest_get("getIP4Address", "containerId=#{@config_id}&address=#{ip}")
|
366
|
+
result2 = JSON.parse(json2)
|
367
|
+
properties2 = parse_properties(result2["properties"])
|
368
|
+
unless properties2["macAddress"].nil?
|
369
|
+
mac_address = properties2["macAddress"].tr("-", ":")
|
370
|
+
hosts.push(Proxy::DHCP::Reservation.new("", ip, mac_address, subnet, {}))
|
371
|
+
end
|
372
|
+
else
|
373
|
+
# host record on ip, return more infos
|
374
|
+
results.each do |result|
|
375
|
+
properties = parse_properties(result["properties"])
|
376
|
+
opts = { hostname: properties["absoluteName"] }
|
377
|
+
|
378
|
+
next unless properties["reverseRecord"].to_s == "true".to_s
|
379
|
+
|
380
|
+
json2 = rest_get("getEntityById", "id=#{ipid}")
|
381
|
+
result2 = JSON.parse(json2)
|
382
|
+
properties2 = parse_properties(result2["properties"])
|
383
|
+
unless properties2["macAddress"].nil?
|
384
|
+
mac_address = properties2["macAddress"].tr("-", ":")
|
385
|
+
hosts.push(Proxy::DHCP::Reservation.new(properties["absoluteName"], ip, mac_address, subnet, opts))
|
386
|
+
end
|
387
|
+
end
|
388
|
+
end
|
389
|
+
hosts.compact
|
390
|
+
end
|
391
|
+
|
392
|
+
# public
|
393
|
+
# fetches all dhcp reservations by a mac
|
394
|
+
def host_by_mac_and_subnet(subnet_of_host, mac)
|
395
|
+
logger.debug("subnet_of_host #{subnet_of_host}")
|
396
|
+
|
397
|
+
net = get_network_by_ip(subnet_of_host)
|
398
|
+
|
399
|
+
logger.debug("net #{net}")
|
400
|
+
|
401
|
+
subnet = IPAddress.parse(net)
|
402
|
+
|
403
|
+
logger.debug("subnet #{subnet} ")
|
404
|
+
|
405
|
+
json = rest_get("getMACAddress", "configurationId=#{@config_id}&macAddress=#{mac}")
|
406
|
+
result = JSON.parse(json)
|
407
|
+
macid = result["id"].to_s
|
408
|
+
return if macid == "0"
|
409
|
+
|
410
|
+
json2 = rest_get("getLinkedEntities", "entityId=#{macid}&type=IP4Address&start=0&count=9999")
|
411
|
+
result2 = JSON.parse(json2)
|
412
|
+
return nil if result2.empty?
|
413
|
+
|
414
|
+
logger.debug("das #{result2}")
|
415
|
+
|
416
|
+
result2.each do |record|
|
417
|
+
properties = parse_properties(record["properties"])
|
418
|
+
ip = IPAddress(properties["address"])
|
419
|
+
|
420
|
+
logger.debug("hier #{subnet.to_string} #{ip.to_string}")
|
421
|
+
|
422
|
+
next unless subnet.include?(ip)
|
423
|
+
|
424
|
+
logger.debug("hier #{record}")
|
425
|
+
|
426
|
+
host = hosts_by_ip(properties["address"])
|
427
|
+
return nil if host.nil?
|
428
|
+
|
429
|
+
logger.debug("da #{host}")
|
430
|
+
return host[0]
|
431
|
+
end
|
432
|
+
|
433
|
+
nil
|
434
|
+
end
|
435
|
+
end
|
436
|
+
end
|
437
|
+
end
|
438
|
+
end
|