| 1 | #--------------------------------------------------------------- |
|---|
| 2 | # Project : pxemngr |
|---|
| 3 | # File : common.py |
|---|
| 4 | # Copyright : 2009-2010 Splitted-Desktop Systems |
|---|
| 5 | # Author : Frederic Lepied |
|---|
| 6 | # Created On : Sun Feb 1 19:03:58 2009 |
|---|
| 7 | #--------------------------------------------------------------- |
|---|
| 8 | |
|---|
| 9 | """Common functions used by scripts and web logic.""" |
|---|
| 10 | |
|---|
| 11 | import sys |
|---|
| 12 | import os |
|---|
| 13 | import re |
|---|
| 14 | import settings |
|---|
| 15 | from pxe.models import * |
|---|
| 16 | |
|---|
| 17 | _MAC_REGEXP = re.compile('^.*\s([0-9a-f:]+)\s.*', re.I) |
|---|
| 18 | _IP_REGEXP = re.compile('^([0-9.]+).*\s[0-9a-f:]+\s.*', re.I) |
|---|
| 19 | |
|---|
| 20 | def ip_to_mac(ip): |
|---|
| 21 | """Lookup a MAC address from an IPV4 address on a live Linux system.""" |
|---|
| 22 | for line in open('/proc/net/arp').readlines(): |
|---|
| 23 | if line.find(ip) != -1: |
|---|
| 24 | res = _MAC_REGEXP.search(line) |
|---|
| 25 | if res: |
|---|
| 26 | return res.group(1) |
|---|
| 27 | return None |
|---|
| 28 | |
|---|
| 29 | def mac_to_ip(mac): |
|---|
| 30 | """Lookup an IPV4 address from a MAC address on a live Linux system.""" |
|---|
| 31 | mac = mac.upper() |
|---|
| 32 | for line in open('/proc/net/arp').readlines(): |
|---|
| 33 | if line.find(mac) != -1: |
|---|
| 34 | res = _IP_REGEXP.search(line) |
|---|
| 35 | if res: |
|---|
| 36 | return res.group(1) |
|---|
| 37 | return None |
|---|
| 38 | |
|---|
| 39 | def get_mac(request): |
|---|
| 40 | """Returns a MAC address corresponding to the IPV4 address of the remote host of the request.""" |
|---|
| 41 | mac = ip_to_mac(request.META['REMOTE_ADDR']) |
|---|
| 42 | if not mac: |
|---|
| 43 | print 'no mac for', request.META['REMOTE_ADDR'] |
|---|
| 44 | raise Http404 |
|---|
| 45 | return mac |
|---|
| 46 | |
|---|
| 47 | def error(str): |
|---|
| 48 | """Print an error and exit with a return code of 1.""" |
|---|
| 49 | sys.stderr.write(str + '\n') |
|---|
| 50 | sys.exit(1) |
|---|
| 51 | |
|---|
| 52 | def simplify_mac(s): |
|---|
| 53 | """Remove : or - between hexa numbers for a MAC address. Always returns the address in lowercase""" |
|---|
| 54 | ss = s.replace('-', '') |
|---|
| 55 | sss = ss.replace(':', '') |
|---|
| 56 | if len(sss) != 12: |
|---|
| 57 | print 'simplify_mac: invalid length (not 12)', sss, len(sss) |
|---|
| 58 | raise ValueError |
|---|
| 59 | return sss.lower() |
|---|
| 60 | |
|---|
| 61 | def mac2filename(m): |
|---|
| 62 | """Returns a filename using the naming convention used by PXE: 01-<mac address separated by - >.""" |
|---|
| 63 | s = '01-' |
|---|
| 64 | for i in range(0, 10, 2): |
|---|
| 65 | s = s + '%s-' % m[i:i+2] |
|---|
| 66 | s = s + '%s' % m[10:12] |
|---|
| 67 | return s |
|---|
| 68 | |
|---|
| 69 | def mac2path(mac): |
|---|
| 70 | """Returns the path of the MAC or IPV4 mask in the file system.""" |
|---|
| 71 | if len(mac) == 12: |
|---|
| 72 | return '%s/%s' % (settings.PXE_ROOT, mac2filename(mac)) |
|---|
| 73 | else: |
|---|
| 74 | return '%s/%s' % (settings.PXE_ROOT, mac) |
|---|
| 75 | |
|---|
| 76 | def create_symlink(src, dst): |
|---|
| 77 | """Creates a symlink removing the destination if it exists before.""" |
|---|
| 78 | if os.path.exists(dst): |
|---|
| 79 | os.unlink(dst) |
|---|
| 80 | os.symlink(src, dst) |
|---|
| 81 | |
|---|
| 82 | def set_next_boot(system, name, abort=True): |
|---|
| 83 | """Sets next boot symlinks in the PXE and stores the value in the database.""" |
|---|
| 84 | try: |
|---|
| 85 | boot_name = BootName.objects.get(name=name) |
|---|
| 86 | except BootName.DoesNotExist: |
|---|
| 87 | if abort: |
|---|
| 88 | error('Boot name %s not defined' % name) |
|---|
| 89 | else: |
|---|
| 90 | raise BootName.DoesNotExist |
|---|
| 91 | |
|---|
| 92 | prof = '%s/%s%s' % (settings.PXE_PROFILES, boot_name.name, settings.PXE_SUFFIX) |
|---|
| 93 | |
|---|
| 94 | name_dst = '%s/%s' % (settings.PXE_ROOT, system.name) |
|---|
| 95 | create_symlink(prof, name_dst) |
|---|
| 96 | for m in MacAddress.objects.filter(system=system): |
|---|
| 97 | dst = mac2path(m.mac) |
|---|
| 98 | create_symlink(system.name, dst) |
|---|
| 99 | |
|---|
| 100 | if system.name == 'default': |
|---|
| 101 | create_symlink(prof, '%s/default' % (settings.PXE_ROOT)) |
|---|
| 102 | |
|---|
| 103 | log = Log(system=system, boot_name=boot_name) |
|---|
| 104 | log.save() |
|---|
| 105 | |
|---|
| 106 | def simplify_ip(ip): |
|---|
| 107 | """Returns a string containing the hexadecimal representation of an IPV4 address or a sub-part.""" |
|---|
| 108 | l = ip.split('.') |
|---|
| 109 | s = '' |
|---|
| 110 | for e in l: |
|---|
| 111 | s = s + '%02X' % int(e) |
|---|
| 112 | return s |
|---|
| 113 | |
|---|
| 114 | if __name__ == "__main__": |
|---|
| 115 | import unittest |
|---|
| 116 | |
|---|
| 117 | class commonTest(unittest.TestCase): |
|---|
| 118 | |
|---|
| 119 | def test1(self): |
|---|
| 120 | """simplify_ip test.""" |
|---|
| 121 | return self.assertEqual(simplify_ip('10.34'), '0A22') |
|---|
| 122 | |
|---|
| 123 | def test2(self): |
|---|
| 124 | """mac2filename test.""" |
|---|
| 125 | return self.assertEqual(mac2filename('001b38710ab6'), '01-00-1b-38-71-0a-b6') |
|---|
| 126 | |
|---|
| 127 | def test3(self): |
|---|
| 128 | """simplify_mac test.""" |
|---|
| 129 | return self.assertEqual(simplify_mac('00:1b:38:71:0a:b6'), '001b38710ab6') |
|---|
| 130 | |
|---|
| 131 | def test4(self): |
|---|
| 132 | """simplify_mac test.""" |
|---|
| 133 | return self.assertRaises(ValueError, lambda: simplify_mac('00:1b:38:71:0a')) |
|---|
| 134 | |
|---|
| 135 | unittest.main() |
|---|
| 136 | |
|---|
| 137 | # common.py ends here |
|---|