summaryrefslogtreecommitdiff
path: root/kpov_judge/tasks/isc_dhcp_live_boot/task.py
blob: 70611087e8bf4f3dab432e362b24821e4c7b3087 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
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
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
#!/usr/bin/env python
# -*- coding: utf-8 -*-

# TODO: dokoncaj!
# kpov_random_helpers should be imported by add_assignment.py

instructions = {
    'si':u"""
Postavi štiri navidezne računalnike - simpleArbiter, DHCP_server,
BootableClientA ter BootableClientB. Na simpleArbiter preberi naslove IP_GW, IP_DHCP,
IP_B ter ime datoteke BOOT_FNAME.

Na DHCP_server postavi DHCP strežnik s pomočjo ISC dhcp 3 na naslovu IP_DHCP.
SimpleArbiter naj dobi IP_GW. DHCP_server naj ga uporabi kot gateway.

Če se zaganja BootableClientB, naj se sistem zažene v datoteko z imenom BOOT_FNAME.
Če se zaganja katerikoli drug, naj se sistem zažene z live USB in dobi svoj IP. USB je priklopljen na DHCP_server. Datoteke z nastavitvami za PXELinux MORAJO biti dostopne na korenskem imeniku strežnika TFTP.

Tako BootableClientA kot BootableClientB naj bosta brez diskov.
""", 
    
    'en': """Set up 4 virtual computers - simpleArbiter, DHCP_server, BootableClientA and 
BootableClientB. On simpleArbiter read the following IPs: IP_GW, IP_DHCP, IP_B as well as the name of the file BOOT_FNAME.

On DHCP server install a DHCP server using ISC DHCP 3 for the address IP_DHCP.
Simple Arbiter should be given the IP_GW address. DHCP_server should user it a s gateway.

If the BootableClientB is starting, let it boot into a file called BOOT_FNAME.
If any other machine is starting, let it boot suign a live USB and get it's IP. USB should be connected to DHCP_server. Files with PXElinux configuration settings must be accesible from the root directory on the TFTP server.

Both BootableCLientA and B should be diskless.

"""
}
computers = {
    'DHCPServer': {
        'disks': [
            {   'name': 'DHCPServer',
            },
            {   'name': 'bootable_usb',
                'options':{'readonly': True},
                'parts': [ {'dev': 'sdb1', 'path':'/mnt'} ],
            },
            #{   'name': 'CDROM',
            #    'options':{'readonly': True},
            #    'parts': [],# no parts, no mounting.
            #}
        ],
        'network_interfaces': [{'network': 'net1'}],
        'flavor': 'm1.tiny',
        'config_drive': False
    },
    'BootableClientA': {
        'disks': [
        ],
        'network_interfaces': [{'network': 'net1'}],
        'flavor': 'm1.tiny',
        'config_drive': False
    },
    'BootableClientB': {
        'disks': [
        ],
        'network_interfaces': [{'network': 'net1'}],
        'flavor': 'm1.tiny',
        'config_drive': False
    },
    'SimpleArbiter': {
        'disks': [
            {   'name': 'simpleArbiterGW',
            },
            #{   'name': 'CDROM',
            #    'options': {'readonly': True},
            #    'parts': [{'dev': 'b1', 'path': '/cdrom'}],
            #},
        ],
        'network_interfaces': [{'network': 'net1'}, {'network': 'test-net'}],
        'flavor': 'm1.tiny',
        'config_drive': False
    }
}

networks = { 'net1': {'public': False}, 'test-net': {'public': True} }

params_meta = {
    'IP_DHCP': {'descriptions': {'si': 'IP DHCP streznika'}, 'w': False, 'public': True, 'type':'IP', 'generated': True},
    'IP_GW': {'descriptions': {'si': 'IP SimpleArbiterja'}, 'w': False, 'public': True, 'type':'IP', 'generated': True},
    'MAC_BOOT': {'descriptions': {'si': 'MAC racunalnika, ki se zazene z ISO'}, 'w': True, 'public': True, 'type':'MAC', 'generated': False},
    # 'IP_BOOT': {'descriptions': {'si': 'IP racunalnika, ki se zazene z ISO'}, 'w': True, 'public': True, 'type':'IP', 'generated': False},
    'TFTP_STRING': {'descriptions': {'si': 'vsebina'}, 'w': False, 'public': False, 'type':'short', 'generated': True},
    'BOOT_FNAME': {'descriptions': {'si': 'Ime datoteke'}, 'w': False, 'public': True, 'type': 'filename', 'generated': True},
}

def task(IP_DHCP, IP_GW, MAC_BOOT, BOOT_FNAME):
    # check the IP
    # TODO (polz): Do not use tabs instead of spaces!
    import pexpect
    import re
    import tftpy
    import StringIO
    results={}
    # TODO (polz): Please use pexpect instead of os.system, it's much nicer.
    # Also, test your functions. This function was obviously never run.
    # 
    # check whether the fname served by the dhcp server is
    # correct
    # you should check the DHCP response from the server.
    # You can use dhcpdump to get some packets, dhcping to create a
    # DHCP Request. You may also use any other tool.
    # If you choose to use dhcping, do not forget to set the hw address 
    # and ip arguments. You can simply feed it MAC_BOOT and IP_BOOT.
    # dhcping -h MAC_BOOT -c IP_BOOT -V -r
    # could work (but you should test it)
    dhcpdump = pexpect.spawn("sudo dhcpdump -i eth1")
    mac_str = pexpect.run("ip link show eth1")
    mac_re = re.search(r"(([0-9a-f]{2}:){5}[0-9a-f]{2})", mac_str)
    mac_SA = mac_re.group(1)
    results['dhcping_other'] = pexpect.run('sudo dhcping -s {} -h {}'.format(
        IP_DHCP, MAC_BOOT))
    dhcpdump.expect('---------------------------------------------------------------------------')
    results['dhcpdump_other_req'] = dhcpdump.before
    dhcpdump.expect('---------------------------------------------------------------------------')
    results['dhcpdump_other_reply'] = dhcpdump.before
    dhcpdump.expect('---------------------------------------------------------------------------')
    results['dhcpdump_other_release'] = dhcpdump.before
    results['dhcping_SA'] = pexpect.run('sudo dhcping -s {} -h {}'.format(
        IP_DHCP, mac_SA))
    dhcpdump.expect('---------------------------------------------------------------------------')
    results['dhcpdump_SA_req'] = dhcpdump.before
    dhcpdump.expect('---------------------------------------------------------------------------')
    results['dhcpdump_SA_reply'] = dhcpdump.before
    dhcpdump.expect('---------------------------------------------------------------------------')
    results['dhcpdump_SA_release'] = dhcpdump.before
    dhcpdump.sendintr()
    tftp_client = pexpect.spawn('tftp {}'.format(IP_DHCP))
    tftp_client.sendline('get pxelinux.cfg/default /dev/stdout')
    tftp_client.expect(r'Received \d* bytes in \d*\.\d* seconds')
    results['tftp_string'] = tftp_client.before
    # check whether the fname served by the dhcp server is correct
    # connect to the service in the special ISO
    # check the MAC of the server on IP_BOOT
    return results
    
def gen_params(user_id, params_meta):
    params = dict()
    r = random.Random(user_id)
    net = kpov_random_helpers.IPv4_subnet_gen(r, '10.64.0.0/10', 24)
    params['IP_DHCP'], params['IP_GW'] = kpov_random_helpers.IPv4_addr_gen(r, net, 2)
    params['BOOTA_FNAME'] = kpov_random_helpers.fname_gen(r)
    params['TFTP_STRING'] = kpov_random_helpers.alnum_gen(r, 45) 
    # IP_NM, DNS_NM, IP_static, DNS_static)
    return params

def task_check(results, params):
    import re
    score = 0
    
    #TO FINISH SCORING WE REQUIRE DICT KEYS AND FUNCTIONS gen_params AND task TO BE FINISHED
    #POINTS FOR EACH TASK MAY BE ADJUSTED IN THE FUTURE
    if results['dhcping_other'].find(params['IP_DHCP']) >= 0:
        score += 1
    if results['dhcping_other'].find(params['IP_DHCP']) >= 0:
        score += 1
    p = re.search(r"FNAME:(.*)\r",
        results['dhcpdump_other_reply'])
    other_fname = p.group(1)
    if other_fname == params['BOOT_FNAME']:
        score += 3
    p = re.search(r"FNAME:(.*)\r",
        results['dhcpdump_SA_reply'])
    sa_fname = p.group(1)
    if sa_fname == params['BOOT_FNAME']:
        score += 3
    if results['tftp_string'].split('\r\r\n')[-2] == "# " + params['TFTP_STRING']:
        score += 2
    return score

def prepare_disks(templates, params):
#    d = templates['simpleArbiterDhcp']
    d = templates['DHCPServer']
    s = """# use this exact config for your booting clients.
# search path for the c32 support libraries (libcom32, libutil etc.)
path
include menu.cfg
default vesamenu.c32
prompt 0
timeout 0
# {}""".format(params['TFTP_STRING'])
    d.write('/mnt/syslinux.cfg', s)