#!/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 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 živega USB, ki ga predstavlja slika diska bootable_usb, ime datoteke z zagonskim nalagalnikom pa naj bo kakršno koli razen {BOOT_FNAME}. Živi USB priklopite na na DHCP_server ter z njega poberite datoteke, potrebne za zagon. Datoteke z nastavitvami za PXELinux, ki jih najdete na živem USB, MORAJO biti dostopne na korenskem imeniku strežnika TFTP. Tako BootableClientA kot BootableClientB naj bosta brez diskov. """, # TODO: write a proper translation. The one that used to be here was just wrong. 'en': """Set up 4 virtual computers - simpleArbiter, DHCP_server, BootableClientA and BootableClientB. On DHCP_server, set up a DHCP server using ISC dhcp 3. Set the IP address of this server to {IP_DHCP}. If SimpleArbiter requests an IP, have the DHCP server serve it {IP_GW}. DHCP_server should use SimpleArbiter as it's gateway. If BootableClientB tries to boot over the network, have the DHCP server tell it to boot from the file {BOOT_FNAME}. If any other system tries to boot over the network, have it boot from a live USB drive represented by the disk image bootable_usb and have the bootloader filename be different from {BOOT_FNAME}. Connect the live USB to DHCP_server and copy the files neccessarry for it to boot. The PXELinux configuration files must be the same as the ones found on the live USB and MUST be accessible on the TFTP server root. Both BootableCLientA and BootableClientB should be diskless. """ } computers = { 'DHCPServer': { 'disks': [ { 'name': 'student-DHCPServer', }, { 'name': 'bootable_usb', 'options':{'readonly': False}, '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 import time 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) ip_str = pexpect.run('ip addr show') eth_re_str = r"ether (([0-9a-f]{{2}}:){{5}}[0-9a-f]{{2}})(.*)\r\n(.*){}(.*)\s(\w*)\r\n" # print eth_re_str.format(IP_DHCP) # print ip_str ip_re = re.search(eth_re_str.format(IP_GW), ip_str) mac_SA = ip_re.group(1) eth_dev_SA = ip_re.group(6) dhcpdump = pexpect.spawn("sudo dhcpdump -i {}".format(eth_dev_SA)) time.sleep(2) results['dhcping_other'] = pexpect.run('sudo dhcping -s {} -h {} -c {}'.format( IP_DHCP, MAC_BOOT, IP_GW)) 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 {} -c {}'.format( IP_DHCP, mac_SA, IP_GW)) 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.expect(r'tftp>') tftp_client.sendline('get pxelinux.cfg/default /dev/stdout') tftp_client.expect(r'tftp>') 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['BOOT_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 hints = [] #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 else: hints += ["DHCP wrong"] if results['dhcping_SA'].find(params['IP_DHCP']) >= 0: score += 1 else: hints += ["DHCP wrong"] p = re.search(r"FNAME:(.*)\.\r", results['dhcpdump_other_reply']) if p is not None: other_fname = p.group(1).strip() else: other_fname = '' if other_fname == params['BOOT_FNAME']: score += 3 else: hints += ["special fname wrong:" + other_fname] p = re.search(r"FNAME:(.*)\.\r", results['dhcpdump_SA_reply']) if p is not None: sa_fname = p.group(1).strip() else: sa_fname = '' if sa_fname != params['BOOT_FNAME']: score += 3 else: hints += ["fname wrong:" + sa_fname] try: special_tftp = "# " + params['TFTP_STRING'] tftp_end = results['tftp_string'].split('\r\r\n')[-1] assert tftp_end[:len(special_tftp)] == special_tftp score += 2 except: hints += ["tftp wrong"] return score, hints def prepare_disks(templates, task_params, global_params): # d = templates['simpleArbiterDhcp'] d = templates['student-DHCPServer'] s = """# {}""".format(task_params['TFTP_STRING']) d = templates['bootable_usb'] d.write_append('/mnt/syslinux.cfg', s) d = templates['simpleArbiterGW'] s = """auto lo iface lo inet loopback auto ens3 iface ens3 inet dhcp auto enp0s3 iface enp0s3 inet dhcp auto ens4 iface ens4 inet static address {IP_GW} netmask 255.192.0.0 auto enp0s8 iface enp0s8 inet static address {IP_GW} netmask 255.192.0.0 """.format(IP_GW = task_params['IP_GW']) d.write("/etc/network/interfaces", s) write_default_config(templates['simpleArbiterGW'], global_params)