smart_proxy_dhcp_bluecat 0.1.0 → 0.1.5

Sign up to get free protection for your applications and to get access to all the features.
metadata CHANGED
@@ -1,56 +1,56 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: smart_proxy_dhcp_bluecat
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Matthias Hähnel
8
8
  - The Foreman Team
9
- autorequire:
9
+ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2019-10-17 00:00:00.000000000 Z
12
+ date: 2021-02-23 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: httparty
16
16
  requirement: !ruby/object:Gem::Requirement
17
17
  requirements:
18
- - - '>='
18
+ - - ">="
19
19
  - !ruby/object:Gem::Version
20
20
  version: '0'
21
21
  type: :runtime
22
22
  prerelease: false
23
23
  version_requirements: !ruby/object:Gem::Requirement
24
24
  requirements:
25
- - - '>='
25
+ - - ">="
26
26
  - !ruby/object:Gem::Version
27
27
  version: '0'
28
28
  - !ruby/object:Gem::Dependency
29
29
  name: ipaddress
30
30
  requirement: !ruby/object:Gem::Requirement
31
31
  requirements:
32
- - - '>='
32
+ - - ">="
33
33
  - !ruby/object:Gem::Version
34
34
  version: '0'
35
35
  type: :runtime
36
36
  prerelease: false
37
37
  version_requirements: !ruby/object:Gem::Requirement
38
38
  requirements:
39
- - - '>='
39
+ - - ">="
40
40
  - !ruby/object:Gem::Version
41
41
  version: '0'
42
42
  - !ruby/object:Gem::Dependency
43
43
  name: rubocop
44
44
  requirement: !ruby/object:Gem::Requirement
45
45
  requirements:
46
- - - ~>
46
+ - - "~>"
47
47
  - !ruby/object:Gem::Version
48
48
  version: 0.50.0
49
49
  type: :development
50
50
  prerelease: false
51
51
  version_requirements: !ruby/object:Gem::Requirement
52
52
  requirements:
53
- - - ~>
53
+ - - "~>"
54
54
  - !ruby/object:Gem::Version
55
55
  version: 0.50.0
56
56
  description: BlueCat DHCP provider plugin for Foreman's smart proxy
@@ -61,48 +61,39 @@ executables: []
61
61
  extensions: []
62
62
  extra_rdoc_files: []
63
63
  files:
64
+ - LICENSE
65
+ - README.md
66
+ - bundler.d/dhcp_bluecat.rb
64
67
  - config/dhcp_bluecat.yml.example
65
68
  - lib/smart_proxy_dhcp_bluecat.rb
69
+ - lib/smart_proxy_dhcp_bluecat/bluecat_api.rb
66
70
  - lib/smart_proxy_dhcp_bluecat/dhcp_bluecat_main.rb
67
71
  - lib/smart_proxy_dhcp_bluecat/dhcp_bluecat_plugin.rb
68
72
  - lib/smart_proxy_dhcp_bluecat/dhcp_bluecat_version.rb
69
73
  - lib/smart_proxy_dhcp_bluecat/module_loader.rb
70
74
  - lib/smart_proxy_dhcp_bluecat/plugin_configuration.rb
71
75
  - lib/smart_proxy_dhcp_bluecat/settings_validator.rb
72
- - lib/smart_proxy_dhcp_bluecat/bluecat_api.rb
73
- - lib/lib/smart_proxy_dhcp_bluecat/bluecat_api.rb
74
- - lib/lib/smart_proxy_dhcp_bluecat/dhcp_bluecat_main.rb
75
- - lib/lib/smart_proxy_dhcp_bluecat/dhcp_bluecat_plugin.rb
76
- - lib/lib/smart_proxy_dhcp_bluecat/dhcp_bluecat_version.rb
77
- - lib/lib/smart_proxy_dhcp_bluecat/module_loader.rb
78
- - lib/lib/smart_proxy_dhcp_bluecat/plugin_configuration.rb
79
- - lib/lib/smart_proxy_dhcp_bluecat/settings_validator.rb
80
- - lib/lib/smart_proxy_dhcp_bluecat.rb
81
- - bundler.d/dhcp_bluecat.rb
82
- - README.md
83
- - LICENSE
84
76
  homepage: https://github.com/theforeman/smart_proxy_dhcp_bluecat
85
77
  licenses:
86
78
  - GPL-3.0
87
79
  metadata: {}
88
- post_install_message:
80
+ post_install_message:
89
81
  rdoc_options: []
90
82
  require_paths:
91
83
  - lib
92
84
  required_ruby_version: !ruby/object:Gem::Requirement
93
85
  requirements:
94
- - - '>='
86
+ - - ">="
95
87
  - !ruby/object:Gem::Version
96
88
  version: '0'
97
89
  required_rubygems_version: !ruby/object:Gem::Requirement
98
90
  requirements:
99
- - - '>='
91
+ - - ">="
100
92
  - !ruby/object:Gem::Version
101
93
  version: '0'
102
94
  requirements: []
103
- rubyforge_project:
104
- rubygems_version: 2.0.14.1
105
- signing_key:
95
+ rubygems_version: 3.1.2
96
+ signing_key:
106
97
  specification_version: 4
107
98
  summary: BlueCat DHCP provider plugin for Foreman's smart proxy
108
99
  test_files: []
@@ -1,11 +0,0 @@
1
- module Proxy
2
- module DHCP
3
- module BlueCat; end
4
- end
5
- end
6
-
7
- require 'smart_proxy_dhcp_bluecat/plugin_configuration'
8
- require 'smart_proxy_dhcp_bluecat/module_loader'
9
- require 'smart_proxy_dhcp_bluecat/settings_validator'
10
- require 'smart_proxy_dhcp_bluecat/dhcp_bluecat_version'
11
- require 'smart_proxy_dhcp_bluecat/dhcp_bluecat_plugin'
@@ -1,345 +0,0 @@
1
- require 'httparty'
2
- require 'ipaddress'
3
- require 'json'
4
-
5
- class BlueCat::Client
6
- include ::Proxy::Log
7
-
8
- @@token = ''
9
-
10
- attr_reader :scheme, :verify, :host, :parent_block, :view_name, :config_name, :config_id, :server_id, :username, :password
11
-
12
- def initialize(scheme, verify, host, parent_block, view_name, config_name, config_id, server_id, username, password)
13
- @scheme = scheme
14
- @verify = verify
15
- @host = host
16
- @parent_block = parent_block
17
- @view_name = view_name
18
- @config_name = config_name
19
- @config_id = config_id
20
- @server_id = server_id
21
- @username = username
22
- @password = password
23
- end
24
-
25
- def rest_login
26
- # login to bam, parse the session token
27
- logger.debug('BAM Login ' + @scheme + ' ' + @host + ' ')
28
- response = HTTParty.get(format('%s://%s/Services/REST/v1/login?username=%s&password=%s', @scheme, @host, @username, @password),
29
- headers: { 'Content-Type' => 'text/plain' },
30
- verify => @verify)
31
- if response.code != 200
32
- logger.error('BAM Login Failed. HTTP' + response.code.to_s + ' ' + response.body.to_s)
33
- end
34
- body = response.body.to_s
35
- token = body.match(/BAMAuthToken:\s+(\S+)/).captures
36
-
37
- logger.debug('BAM Login Body ' + response.body)
38
- logger.debug('BAM Login Token ' + token[0].to_s)
39
- @@token = token[0].to_s
40
- end
41
-
42
- def rest_logout
43
- # logout from bam,
44
- logger.debug('BAM Logout ')
45
- response = HTTParty.get(format('%s://%s/Services/REST/v1/logout', @scheme, @host),
46
- headers: { 'Authorization' => 'BAMAuthToken: ' + @@token, 'Content-Type' => 'application/json' },
47
- verify: @verify)
48
- if response.code != 200
49
- logger.error('BAM Logout Failed. HTTP' + response.code.to_s + ' ' + response.body.to_s)
50
- end
51
- end
52
-
53
- def rest_get(endpoint, querystring)
54
- # wrapper function to for rest get requests
55
- logger.debug('BAM GET ' + endpoint + '?' + querystring)
56
-
57
- response = HTTParty.get(format('%s://%s/Services/REST/v1/%s?%s', @scheme, @host, endpoint, querystring),
58
- headers: { 'Authorization' => 'BAMAuthToken: ' + @@token, 'Content-Type' => 'application/json' },
59
- verify: @verify)
60
- # Session propably expired, refresh it and do the request again
61
- if response.code == 401
62
- rest_login
63
- response = HTTParty.get(format('%s://%s/Services/REST/v1/%s?%s', @scheme, @host, endpoint, querystring),
64
- headers: { 'Authorization' => 'BAMAuthToken: ' + @@token, 'Content-Type' => 'application/json' },
65
- verify: @verify)
66
- end
67
-
68
- if response.code != 200
69
- logger.error('BAM GET Failed. HTTP' + response.code.to_s + ' ' + response.body.to_s)
70
- return nil
71
- end
72
-
73
- response.body
74
- end
75
-
76
- def rest_post(endpoint, querystring)
77
- # wrapper function to for rest post requests
78
- logger.debug('BAM POST ' + endpoint + '?' + querystring)
79
- response = HTTParty.post(format('%s://%s/Services/REST/v1/%s?%s', @scheme, @host, endpoint, querystring),
80
- headers: { 'Authorization' => 'BAMAuthToken: ' + @@token, 'Content-Type' => 'application/json' },
81
- verify: @verify
82
- )
83
- # Session propably expired, refresh it and do the request again
84
- if response.code == 401
85
- rest_login
86
- response = HTTParty.post(format('%s://%s/Services/REST/v1/%s?%s', @scheme, @host, endpoint, querystring),
87
- headers: { 'Authorization' => 'BAMAuthToken: ' + @@token, 'Content-Type' => 'application/json' },
88
- verify: @verify)
89
- end
90
- if response.code != 200
91
- logger.error('BAM POST Failed. HTTP' + response.code.to_s + ' ' + response.body.to_s)
92
- return nil
93
- else
94
- return response.body
95
- end
96
- end
97
-
98
- def rest_put(endpoint, querystring)
99
- # wrapper function to for rest put requests
100
- logger.debug('BAM PUT ' + endpoint + '?' + querystring)
101
- response = HTTParty.put(format('%s://%s/Services/REST/v1/%s?%s', @scheme, @host, endpoint, querystring),
102
- headers: { 'Authorization' => 'BAMAuthToken: ' + @@token, 'Content-Type' => 'application/json' },
103
- verify: @verify)
104
- # Session propably expired, refresh it and do the request again
105
- if response.code == 401
106
- rest_login
107
- response = HTTParty.put(format('%s://%s/Services/REST/v1/%s?%s', @scheme, @host, endpoint, querystring),
108
- headers: { 'Authorization' => 'BAMAuthToken: ' + @@token, 'Content-Type' => 'application/json' },
109
- verify: @verify)
110
- end
111
- if response.code != 200
112
- logger.error('BAM PUT Failed. HTTP' + response.code.to_s + ' ' + response.body.to_s)
113
- return nil
114
- else
115
- return response.body
116
- end
117
- end
118
-
119
- def rest_delete(endpoint, querystring)
120
- # wrapper function to for rest delete requests
121
- logger.debug('BAM DELETE ' + endpoint + '?' + querystring)
122
- response = HTTParty.delete(format('%s://%s/Services/REST/v1/%s?%s', @scheme, @host, endpoint, querystring),
123
- headers: { 'Authorization' => 'BAMAuthToken: ' + @@token, 'Content-Type' => 'application/json' },
124
- verify: @verify)
125
-
126
- # Session propably expired, refresh it and do the request again
127
- if response.code == 401
128
- rest_login
129
- response = HTTParty.delete(format('%s://%s/Services/REST/v1/%s?%s', @scheme, @host, endpoint, querystring),
130
- headers: { 'Authorization' => 'BAMAuthToken: ' + @@token, 'Content-Type' => 'application/json' },
131
- verify: @verify)
132
- end
133
- if response.code != 200
134
- logger.error('BAM DELETE Failed. HTTP' + response.code.to_s + ' ' + response.body.to_s)
135
- return nil
136
- else
137
- return response.body
138
- end
139
- end
140
-
141
- def get_addressid_by_ip(ip)
142
- # helper function to get the object id of a ip by an ip address
143
- json = rest_get('getIP4Address', 'containerId=' + @config_id.to_s + '&address=' + ip)
144
- result = JSON.parse(json)
145
- return nil if result.empty?
146
- result['id'].to_s
147
- end
148
-
149
- def get_networkid_by_ip(ip)
150
- # helper function to get the object id of a subnet by an ip address
151
- logger.debug('BAM get_networkid_by_ip ' + ip)
152
- querystring = 'containerId=' + @config_id.to_s + '&type=IP4Network' + '&address=' + ip.to_s
153
- json = rest_get('getIPRangedByIP', querystring)
154
- result = JSON.parse(json)
155
- return nil if result.empty?
156
- result['id'].to_s
157
- end
158
-
159
- def get_network_by_ip(ip)
160
- # helper function to get the whole subnet informarions by an ip address
161
- logger.debug('BAM get_network_by_ip ' + ip)
162
- querystring = 'containerId=' + @config_id.to_s + '&type=IP4Network' + '&address=' + ip.to_s
163
- json = rest_get('getIPRangedByIP', querystring)
164
- result = JSON.parse(json)
165
- properties = parse_properties(result['properties'])
166
- properties['CIDR'].to_s
167
- end
168
-
169
- def parse_properties(properties)
170
- # helper function to parse the properties scheme of bluecat into a hash
171
- # => properies: a string that contains properties for the object in attribute=value format, with each separated by a | (pipe) character.
172
- # For example, a host record object may have a properties field such as ttl=123|comments=my comment|.
173
- properties = properties.split('|')
174
- h = {}
175
- properties.each do |property|
176
- h[property.split('=').first.to_s] = property.split('=').last.to_s
177
- end
178
- h
179
- end
180
-
181
- # public
182
- def add_host(options)
183
- # wrapper function to add the dhcp reservation and dns records
184
-
185
- # add the ip and hostname and mac as static
186
- rest_post('addDeviceInstance', 'configName=' + @config_name +
187
- '&ipAddressMode=PASS_VALUE' \
188
- '&ipEntity=' + options['ip'] +
189
- '&viewName=' + @view_name +
190
- '&zoneName=' + options['hostname'].split('.', 2).last +
191
- '&deviceName=' + options['hostname'] +
192
- '&recordName=' + options['hostname'] +
193
- '&macAddressMode=PASS_VALUE' \
194
- '&macEntity=' + options['mac'] +
195
- '&options=AllowDuplicateHosts=true%7C')
196
-
197
- address_id = get_addressid_by_ip(options['ip'])
198
-
199
- # update the state of the ip from static to dhcp reserved
200
- rest_put('changeStateIP4Address', 'addressId=' + address_id +
201
- '&targetState=MAKE_DHCP_RESERVED' \
202
- '&macAddress=' + options['mac'])
203
- # deploy the config
204
- rest_post('deployServerConfig', 'serverId=' + @server_id.to_s + '&properties=services=DHCP')
205
- # lets wait a little bit for the complete dhcp deploy
206
- sleep 3
207
- rest_post('deployServerConfig', 'serverId=' + @server_id.to_s + '&properties=services=DNS')
208
- nil
209
- end
210
-
211
- # public
212
- def remove_host(ip)
213
- # wrapper function to remove a dhcp reservation and dns records
214
- # deploy the config, without a clean config the removal fails sometimes
215
- rest_post('deployServerConfig', 'serverId=' + @server_id.to_s + '&properties=services=DHCP,DNS')
216
- # remove the ip and depending records
217
- rest_delete('deleteDeviceInstance', 'configName=' + @config_name + '&identifier=' + ip)
218
- # deploy the config again
219
- rest_post('deployServerConfig', 'serverId=' + @server_id.to_s + '&properties=services=DHCP,DNS')
220
- end
221
-
222
- # public
223
- def get_next_ip(netadress, start_ip, _end_ip)
224
- # fetches the next free address in a subnet
225
- networkid = get_networkid_by_ip(netadress)
226
-
227
- start_ip = IPAddress.parse(netadress).first if start_ip.to_s.empty?
228
-
229
- properties = 'offset=' + start_ip.to_s + '%7CexcludeDHCPRange=false'
230
- result = rest_get('getNextIP4Address', 'parentId=' + networkid.to_s + '&properties=' + properties)
231
- return if result.empty?
232
- result.tr('"', '')
233
- end
234
-
235
- # public
236
- def get_subnets
237
- # fetches all subnets under the parent_block
238
- json = rest_get('getEntities', 'parentId=' + @parent_block.to_s + '&type=IP4Network&start=0&count=10000')
239
- results = JSON.parse(json)
240
- subnets = []
241
- subnets = results.map do |result|
242
- properties = parse_properties(result['properties'])
243
- net = IPAddress.parse(properties['CIDR'])
244
- opts = { routers: [properties['gateway']] }
245
- ::Proxy::DHCP::Subnet.new(net.address, net.netmask, opts)
246
- end
247
- subnets.compact
248
- end
249
-
250
- # public
251
- def find_mysubnet(subnet_address)
252
- # fetches a subnet by its network address
253
- net = IPAddress.parse(get_network_by_ip(subnet_address))
254
- subnet = ::Proxy::DHCP::Subnet.new(net.address, net.netmask)
255
- subnet
256
- end
257
-
258
- # public
259
- def get_hosts(network_address)
260
- # fetches all dhcp reservations in a subnet
261
- netid = get_networkid_by_ip(network_address)
262
- net = IPAddress.parse(get_network_by_ip(network_address))
263
- subnet = ::Proxy::DHCP::Subnet.new(net.address, net.netmask)
264
-
265
- json = rest_get('getNetworkLinkedProperties', 'networkId=' + netid.to_s)
266
- results = JSON.parse(json)
267
-
268
- hosts = []
269
- results.each do |result|
270
- properties = parse_properties(result['properties'])
271
-
272
- # Static Addresses and Gateway are not needed here
273
- # if properties.length() >= 4
274
- # if properties["state"] == "Gateway" or properties["state"] == "Static"
275
- # address = properties[0].split("=").last()
276
- # macAddress = "00:00:00:00:00:00"
277
- # hosttag = properties[3].split("=").last().split(":")
278
- # name = hosttag[1] + "." + hosttag[3]
279
- # opts = {:hostname => name}
280
- # hosts.push(Proxy::DHCP::Reservation.new(name, address, macAddress, subnet, opts))
281
- # end
282
- # end
283
- next unless properties.length >= 5
284
- next unless properties['state'] == 'DHCP Reserved'
285
- hosttag = properties['host'].split(':')
286
- name = hosttag[1] + '.' + hosttag[3]
287
- opts = { hostname: name }
288
- hosts.push(Proxy::DHCP::Reservation.new(name, properties['address'], properties['macAddress'].tr('-', ':'), subnet, opts))
289
- end
290
- hosts.compact
291
- end
292
-
293
- # public
294
- def get_hosts_by_ip(ip)
295
- # fetches a host by its ip
296
- hosts = []
297
- net = IPAddress.parse(get_network_by_ip(ip))
298
- subnet = ::Proxy::DHCP::Subnet.new(net.address, net.netmask)
299
- ipid = get_addressid_by_ip(ip)
300
- return nil if ipid.to_s == '0'
301
- json = rest_get('getLinkedEntities', 'entityId=' + ipid + '&type=HostRecord&start=0&count=2')
302
- results = JSON.parse(json)
303
-
304
- if results.empty?
305
- # no host record on ip, fetch mac only
306
- json2 = rest_get('getIP4Address', 'containerId=' + @config_id.to_s + '&address=' + ip)
307
- result2 = JSON.parse(json2)
308
- properties2 = parse_properties(result2['properties'])
309
- mac_address = properties2['macAddress'].tr('-', ':')
310
- hosts.push(Proxy::DHCP::Reservation.new("", ip, mac_address, subnet, {}))
311
- else
312
- # host record on ip, return more infos
313
- results.each do |result|
314
- properties = parse_properties(result['properties'])
315
- opts = { hostname: properties['absoluteName'] }
316
-
317
- next unless properties['reverseRecord'].to_s == 'true'.to_s
318
- json2 = rest_get('getEntityById', 'id=' + ipid)
319
- result2 = JSON.parse(json2)
320
- properties2 = parse_properties(result2['properties'])
321
- mac_address = properties2['macAddress'].tr('-', ':')
322
- unless mac_address.empty?
323
- hosts.push(Proxy::DHCP::Reservation.new(properties['absoluteName'], ip, mac_address, subnet, opts))
324
- end
325
- end
326
- end
327
- hosts.compact
328
- end
329
-
330
- # public
331
- def get_host_by_mac(mac)
332
- # fetches all dhcp reservations by a mac
333
- json = rest_get('getMACAddress', 'configurationId=' + @config_id.to_s + '&macAddress=' + mac.to_s)
334
- result = JSON.parse(json)
335
- macid = result['id'].to_s
336
- return if macid == '0'
337
- json2 = rest_get('getLinkedEntities', 'entityId=' + macid + '&type=IP4Address&start=0&count=1')
338
- result2 = JSON.parse(json2)
339
- return if result2.empty?
340
- properties = parse_properties(result2[0]['properties'])
341
- host = get_hosts_by_ip(properties['address'])
342
- return if host.nil?
343
- host[0]
344
- end
345
- end