138 hostname = host |
143 hostname = host |
139 |
144 |
140 if hostname : |
145 if hostname : |
141 yield hostname, 'ethernet', ethernet |
146 yield hostname, 'ethernet', ethernet |
142 |
147 |
143 def process_dhcp_hosts (options, blocks) : |
148 def import_dhcp_hosts (options, blocks) : |
144 """ |
149 """ |
145 Process hosts from a parsed block |
150 Process hosts from a parsed block |
146 """ |
151 """ |
147 |
152 |
148 for block, items, blocks in blocks : |
153 for block, items, blocks in blocks : |
149 log.info("%s", block) |
154 log.info("%s", block) |
150 |
155 |
151 block, args = block[0], block[1:] |
156 block, args = block[0], block[1:] |
152 |
157 |
153 if block == 'group' : |
158 if block == 'group' : |
154 for info in process_dhcp_hosts(options, blocks) : |
159 for info in import_dhcp_hosts(options, blocks) : |
155 yield info |
160 yield info |
156 elif block == 'host' : |
161 elif block == 'host' : |
157 host, = args |
162 host, = args |
158 |
163 |
159 try : |
164 try : |
160 for info in process_dhcp_host(options, host, items) : |
165 for info in import_dhcp_host(options, host, items) : |
161 yield info |
166 yield info |
162 except ValueError as error : |
167 except ValueError as error : |
163 log.warn("%s: invalid host: %s", host, error) |
168 log.warn("%s: invalid host: %s", host, error) |
164 else: |
169 else: |
165 log.warn("ignore unknown block: %s", block) |
170 log.warn("ignore unknown block: %s", block) |
166 |
171 |
167 def process_dhcp_conf (options, file) : |
172 def import_dhcp_conf (options, file) : |
168 items, blocks = pvl.dhcp.config.DHCPConfigParser().load(file) |
173 items, blocks = pvl.dhcp.config.DHCPConfigParser().load(file) |
169 |
174 |
170 for item in items : |
175 for item in items : |
171 item, args = item[0], item[1:] |
176 item, args = item[0], item[1:] |
172 |
177 |
173 if item == 'include' : |
178 if item == 'include' : |
174 include, = args |
179 include, = args |
175 for info in process_dhcp_conf(options, pvl.args.apply_file(include)) : |
180 for info in import_dhcp_conf(options, pvl.args.apply_file(include)) : |
176 yield info |
181 yield info |
177 else : |
182 else : |
178 log.warn("ignore unknown item: %s", item) |
183 log.warn("ignore unknown item: %s", item) |
179 |
184 |
180 for info in process_dhcp_hosts(options, blocks) : |
185 for info in import_dhcp_hosts(options, blocks) : |
181 yield info |
186 yield info |
182 |
|
183 def apply_hosts_import (options) : |
|
184 """ |
|
185 Import host infos from given files. |
|
186 """ |
|
187 |
|
188 if options.import_zone_hosts: |
|
189 for info in process_zone_hosts(options, |
|
190 pvl.args.apply_file(options.import_zone_hosts)) : |
|
191 yield info |
|
192 |
|
193 if options.import_dhcp_hosts: |
|
194 for info in process_dhcp_conf(options, |
|
195 pvl.args.apply_file(options.import_dhcp_hosts)) : |
|
196 yield info |
|
197 |
187 |
198 ZONE_COMMENTS = ( |
188 ZONE_COMMENTS = ( |
199 re.compile(r'(?P<owner>[^/]+)\s*-\s+(?P<host>.+)'), |
189 re.compile(r'(?P<owner>[^/]+)\s*-\s+(?P<host>.+)'), |
200 re.compile(r'(?P<group>.+?)\s*/\s*(?P<owner>.+)\s+[/-]\s+(?P<host>.+)'), |
190 re.compile(r'(?P<group>.+?)\s*/\s*(?P<owner>.+)\s+[/-]\s+(?P<host>.+)'), |
201 re.compile(r'(?P<group>.+?)\s*/\s*(?P<owner>.+)\s+[(]\s*(?P<host>.+)[)]'), |
191 re.compile(r'(?P<group>.+?)\s*/\s*(?P<owner>.+)\s+[(]\s*(?P<host>.+)[)]'), |
237 |
227 |
238 for field, value in matches.iteritems() : |
228 for field, value in matches.iteritems() : |
239 if value : |
229 if value : |
240 yield field, value.strip() |
230 yield field, value.strip() |
241 |
231 |
242 HOST_OWNERS = { |
232 NONE_OWNERS = set(( |
243 u'tech': 'root', |
233 u'tech', |
244 u'atk': 'root', |
234 u'atk', |
245 u'toimisto': 'root', |
235 u'toimisto', |
246 } |
236 )) |
247 |
237 |
248 def process_host_owner (options, host, info) : |
238 def process_host_owner_ldap (options, host, info) : |
249 """ |
239 """ |
250 Yield guesses for user from LDAP. |
240 Yield guesses for user from LDAP. |
251 """ |
241 """ |
252 |
|
253 if info.get('owner').lower() in HOST_OWNERS : |
|
254 yield HOST_OWNERS[info.get('owner').lower()] |
|
255 |
242 |
256 if info.get('mail') : |
243 if info.get('mail') : |
257 for user in options.ldap.users.filter( |
244 for user in options.ldap.users.filter( |
258 { 'mailLocalAddress': info['mail'] }, |
245 { 'mailLocalAddress': info['mail'] }, |
259 { 'uid': info['mail'] }, |
246 { 'uid': info['mail'] }, |
260 ) : |
247 ) : |
261 yield user['uid'] |
248 yield user, None |
262 |
249 |
263 if info.get('group') and info.get('owner') : |
250 if info.get('group') and info.get('owner') : |
264 groups = options.ldap.groups.filter(cn=info['group']) |
251 groups = options.ldap.groups.filter(cn=info['group']) |
265 |
252 |
266 for group in groups : |
253 for group in groups : |
267 for user in options.ldap.users.filter({ |
254 for user in options.ldap.users.filter({ |
268 'gidNumber': group['gidNumber'], |
255 'gidNumber': group['gidNumber'], |
269 'cn': info['owner'], |
256 'cn': info['owner'], |
270 }) : |
257 }) : |
271 yield user['uid'] |
258 yield user, group |
272 |
259 |
273 if info.get('owner') : |
260 if info.get('owner') : |
274 for user in options.ldap.users.filter({ |
261 for user in options.ldap.users.filter({ |
275 'cn': info['owner'], |
262 'cn': info['owner'], |
276 }) : |
263 }) : |
277 yield user['uid'] |
264 yield user, None |
|
265 |
|
266 def process_host_owner (options, host, info) : |
|
267 """ |
|
268 Return (owner, comment) for host based on info, or None. |
|
269 """ |
|
270 |
|
271 if info.get('owner').lower() in NONE_OWNERS : |
|
272 return |
|
273 |
|
274 # from ldap? |
|
275 for ldap in process_host_owner_ldap(options, host, info) : |
|
276 user, group = ldap |
|
277 |
|
278 if not group : |
|
279 # get group from ldap |
|
280 group = options.ldap.users.group(user) |
|
281 |
|
282 return user['uid'], u"{group} / {user}".format( |
|
283 user = user.getunicode('cn'), |
|
284 group = group.getunicode('cn'), |
|
285 ) |
278 |
286 |
279 def process_host_comments (options, host, info) : |
287 def process_host_comments (options, host, info) : |
280 """ |
288 """ |
281 Process host fields from comment. |
289 Process host fields from comment. |
282 |
290 |
283 Attempts to find owner from LDAP.. |
291 Attempts to find owner from LDAP.. |
284 """ |
292 """ |
285 |
293 |
286 log.debug("%s: %s", host, info) |
294 log.debug("%s: %s", host, info) |
287 |
295 |
288 for owner in process_host_owner(options, host, info) : |
296 owner = process_host_owner(options, host, info) |
289 log.info("%s: %s", host, owner) |
297 |
290 |
298 if owner : |
|
299 owner, comment = owner |
|
300 |
|
301 log.info("%s: %s (%s)", host, owner, comment) |
|
302 |
|
303 yield 'owner-comment', comment |
291 yield 'owner', owner, |
304 yield 'owner', owner, |
292 |
|
293 # only use the first match |
|
294 break |
|
295 else : |
305 else : |
296 log.warn("%s: no owner: %s", host, info) |
306 log.warn("%s: no owner: %s", host, info) |
297 |
307 |
298 if info.get('host') : |
308 if info.get('host') : |
299 yield 'comment', info['host'] |
309 yield 'comment', info['host'] |
321 ).encode('utf-8') |
331 ).encode('utf-8') |
322 |
332 |
323 |
333 |
324 for field, value in process_host_comments(options, host, fields) : |
334 for field, value in process_host_comments(options, host, fields) : |
325 yield host, field, value |
335 yield host, field, value |
326 |
336 |
327 def process_hosts_import (options, import_hosts) : |
337 def apply_hosts_import (options) : |
328 """ |
338 """ |
329 Import host definitions from given infos |
339 Import host infos from given files. |
330 """ |
340 """ |
331 |
341 |
|
342 if options.import_zone_hosts: |
|
343 for info in import_zone_hosts(options, |
|
344 pvl.args.apply_file(options.import_zone_hosts)) : |
|
345 yield info |
|
346 |
|
347 if options.import_dhcp_hosts: |
|
348 for info in import_dhcp_conf(options, |
|
349 pvl.args.apply_file(options.import_dhcp_hosts)) : |
|
350 yield info |
|
351 |
|
352 def import_hosts (options) : |
|
353 """ |
|
354 Import hosts from dns/dhcp. |
|
355 """ |
|
356 |
|
357 import_hosts = apply_hosts_import(options) |
|
358 import_hosts = process_hosts_comments(options, import_hosts) |
|
359 |
|
360 # gather |
332 hosts = collections.defaultdict(lambda: collections.defaultdict(list)) |
361 hosts = collections.defaultdict(lambda: collections.defaultdict(list)) |
333 |
362 |
334 for host, field, value in import_hosts : |
363 for host, field, value in import_hosts : |
335 hosts[host][field].append(value) |
364 hosts[host][field].append(value) |
336 |
365 |
337 return hosts.iteritems() |
366 return hosts.iteritems() |
338 |
367 |
|
368 def select_hosts_ip (options, hosts, network) : |
|
369 for host, fields in hosts : |
|
370 ip = fields.get('ip') |
|
371 |
|
372 if not ip : |
|
373 continue |
|
374 |
|
375 ip = ipaddr.IPAddress(ip[0]) |
|
376 |
|
377 if ip in network : |
|
378 yield ip, host, fields |
|
379 |
|
380 |
|
381 def export_hosts (options, hosts) : |
|
382 """ |
|
383 Export hosts to file. |
|
384 """ |
|
385 |
|
386 file = pvl.args.apply_file(options.output_hosts, 'w', options.output_charset) |
|
387 |
|
388 if options.output_ip : |
|
389 prefix = ipaddr.IPNetwork(options.output_ip) |
|
390 |
|
391 # filter + sort |
|
392 hosts = [(host, fields) for ip, host, fields in sorted(select_hosts_ip(options, hosts, prefix))] |
|
393 |
|
394 for host, fields in hosts : |
|
395 for comment in fields.get('comment', ()) : |
|
396 print >>file, u"# {comment}".format(comment=comment) |
|
397 |
|
398 print >>file, u"[{host}]".format(host=host) |
|
399 |
|
400 for field, fmt in ( |
|
401 ('ip', None), |
|
402 ('ethernet', None), |
|
403 ('owner', u"\t{field:15} = {value} # {fields[owner-comment][0]}"), |
|
404 ) : |
|
405 if not fmt : |
|
406 fmt = u"\t{field:15} = {value}" |
|
407 |
|
408 for value in fields.get(field, ()) : |
|
409 print >>file, fmt.format(field=field, value=value, fields=fields) |
|
410 |
|
411 print >>file |
339 |
412 |
340 def main (argv) : |
413 def main (argv) : |
341 options, args = parse_options(argv) |
414 options, args = parse_options(argv) |
342 |
415 |
343 options.ldap = pvl.ldap.args.apply(options) |
416 options.ldap = pvl.ldap.args.apply(options) |
345 if args : |
418 if args : |
346 # direct from file |
419 # direct from file |
347 hosts = pvl.args.apply_files(args, 'r', options.input_charset) |
420 hosts = pvl.args.apply_files(args, 'r', options.input_charset) |
348 else : |
421 else : |
349 # import |
422 # import |
350 import_hosts = apply_hosts_import(options) |
423 hosts = import_hosts(options) |
351 import_hosts = process_hosts_comments(options, import_hosts) |
|
352 hosts = process_hosts_import(options, import_hosts) |
|
353 |
424 |
354 # output |
425 # output |
355 if options.output_hosts : |
426 if options.output_hosts : |
356 for host, fields in hosts : |
427 export_hosts(options, hosts) |
357 print host |
|
358 |
|
359 for field, values in fields.iteritems() : |
|
360 for value in values : |
|
361 print "\t", field, "\t", value.encode(options.output_charset) |
|
362 |
|
363 return 0 |
|
364 |
428 |
365 if __name__ == '__main__': |
429 if __name__ == '__main__': |
366 pvl.args.main(main) |
430 pvl.args.main(main) |