#!/usr/bin/python import gtk import gtk.glade import gobject import os import sys import string import socket import fcntl import struct from popen2 import Popen3 # starts network tool from gnome-system-tools and uses icons from there, needs to depend on it class LTSPManager: def __init__(self): self.wTree=gtk.glade.XML ("./ltsp-manager.glade") self.win = self.wTree.get_widget("window1") self.buildwin = self.wTree.get_widget("build_window") self.selectwin = self.wTree.get_widget("select_window") self.win.connect("destroy", lambda w: gtk.main_quit()) close_button = self.wTree.get_widget("close_button") close_button.connect("clicked", lambda w: gtk.main_quit()) help_button = self.wTree.get_widget("help_button") help_button.connect("clicked", lambda w: os.system('firefox http://people.ubuntu.com/~ogra/LTSPManager/')) self.lines=0 self.fulfill_prereq() def initialize(self): self.get_devices() self.set_toggles() self.parse_dhcpd_conf() self.get_keymaps() self.get_kbmodels() self.get_serial_protocols() self.get_videodrivers() self.wTree.get_widget("range_from_entry").connect("focus-out-event", self.compare_range) self.wTree.get_widget("range_to_entry").connect("focus-out-event", self.compare_range) def show_mainwin(self, path): self.root=path self.buildwin.hide() self.selectwin.hide() self.initialize() self.win.show_all() def fulfill_prereq(self): self.win.hide() self.selectwin.hide() self.buildwin.hide() pathlist = self.get_root_path() arch = os.popen('dpkg --print-architecture').read().strip() i=0 if len(pathlist) > 1: self.selectwin.show_all() combo = self.wTree.get_widget("chroot_combo") select_cancel = self.wTree.get_widget("chroot_cancel_button") select_cancel.connect("clicked", lambda w: gtk.main_quit()) select_ok = self.wTree.get_widget("chroot_ok_button") select_ok.connect("clicked", lambda w: self.show_mainwin('/opt/ltsp/'+combo.get_active_text())) for path in pathlist: if path == 'i386' or path == 'powerpc' or path == 'amd64': combo.append_text(path) if path == arch: combo.set_active(i) i=i+1 elif len(pathlist) == 1 and (pathlist[0] == 'i386' or pathlist[0] == 'amd64' or pathlist[0] == 'powerpc'): self.show_mainwin('/opt/ltsp/'+pathlist[0]) else: combo = self.wTree.get_widget("build_arch_selector") build_button = self.wTree.get_widget("build_start_button") build_button.connect("clicked", lambda w: self.build_client(combo.get_active_text())) build_cancel = self.wTree.get_widget("build_cancel_button") build_cancel.connect("clicked", lambda w: self.cleanup(combo.get_active_text())) if arch == 'amd64': archlist = ['amd64', 'i386'] else: archlist = [arch] for item in archlist: combo.append_text(item) combo.set_active(0) self.buildwin.show_all() self.wTree.get_widget("build_help_button").hide() def get_root_path(self): pathlist = os.popen('ls /opt/ltsp/ 2>/dev/null') if pathlist: return pathlist.read().split('\n')[:-1] else: return 0 def cleanup(self, root): dirs = ['proc','sys','var/run','var/lock'] os.system('pkill ltsp-build-client') os.system('pkill debootstrap') for directory in dirs: os.system('umount /opt/ltsp/'+root+'/'+directory+' 2>/dev/null') os.system('rm -rf /opt/ltsp/'+root) sys.exit(0) def build_client(self, arch): progbar = self.wTree.get_widget("build_progressbar") self.wTree.get_widget("build_start_button").set_sensitive(0) self.wTree.get_widget("build_arch_selector").set_sensitive(0) fraction=0 pp=Popen3('/usr/sbin/ltsp-build-client --arch '+arch+' 2>/dev/null') for nn in xrange(2000): while gtk.events_pending(): gtk.main_iteration(True) line = pp.fromchild.readline().strip() if line.startswith('I: '): line = line.lstrip('I: ') out = self.line_filter(line) if out: progbar.set_text(out) step = fraction+0.000666667 #0.000731529 for http, 0.000877193 for cdroms if step > 1.0: step = 1.0 progbar.set_fraction(step) fraction = step progbar.set_fraction(1.0) progbar.set_text('LTSP Setup Done...') gobject.timeout_add(3000, self.show_mainwin('/opt/ltsp/'+arch)) def line_filter(self, line): if line.startswith('Retrieving') or line.startswith('Validating') or line.startswith('Extracting') or line.startswith('Installing') or line.startswith('Unpacking') or line.startswith('Configuring') or line.startswith('Need to get') or line.startswith('Setting up') or line.startswith('Cleaning'): line = line.split('(')[0] if not line.endswith('...'): line=line+'...' self.lines=self.lines+1 return line elif line.startswith('Get:'): line = 'Retrieving '+line.split()[3]+'...' self.lines=self.lines+1 return line else: return def set_toggles(self): # Server nbd_checkbutton = self.wTree.get_widget("nbd_checkbutton") nbd_checkbutton.connect("clicked", lambda w: \ self.toggle([self.wTree.get_widget("swap_hbox")])) # Client input kbd_checkbutton = self.wTree.get_widget("kbd_checkbutton") kbd_checkbutton.connect("clicked", lambda w: \ self.toggle([self.wTree.get_widget("kbd_layout_hbox"), \ self.wTree.get_widget("kbd_model_hbox")])) mouse_checkbutton = self.wTree.get_widget("mouse_checkbutton") mouse_checkbutton.connect("clicked", lambda w: \ self.toggle([self.wTree.get_widget("mousedev_hbox"), \ self.wTree.get_widget("mouseproto_hbox"), \ self.wTree.get_widget("emu_hbox")])) # Client screen noauto_checkbutton = self.wTree.get_widget("noauto_checkbutton") noauto_checkbutton.connect("clicked", lambda w: \ self.toggle([self.wTree.get_widget("hsync_hbox"), \ self.wTree.get_widget("vref_hbox"), \ self.wTree.get_widget("driver_hbox")])) xfs_checkbutton = self.wTree.get_widget("xfs_checkbutton") xfs_checkbutton.connect("clicked", lambda w: \ self.toggle([self.wTree.get_widget("xfs_hbox")])) # LDM ldm_command_checkbutton = self.wTree.get_widget("ldm_command_checkbutton") ldm_command_checkbutton.connect("clicked", lambda w: \ self.toggle([self.wTree.get_widget("ldm_command_hbox")])) env_checkbutton = self.wTree.get_widget("env_checkbutton") env_checkbutton.connect("clicked", lambda w: \ self.toggle([self.wTree.get_widget("env_hbox")])) return True def toggle(self, widgetlist): status = widgetlist[0].get_property('sensitive') if status == True: status = False else: status = True for widget in widgetlist: widget.set_sensitive(status) def get_devices(self): list = [] self.devlist = [] devlist = os.popen("cat /proc/net/dev|grep :|\ awk '{split($0, dev, \":\"); printf \"%s\\n\", \ substr(dev[1], 3)}'|grep -v lo|grep -v sit") list.append(devlist.read().split('\n')) for device in list[0][:-1]: if not self.get_ip(device) == False: self.devlist.append(device) else: # make that a info dialog self.win.set_sensitive(False) dialog = gtk.MessageDialog(self.win, gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, gtk.MESSAGE_INFO, gtk.BUTTONS_OK, None) dialog.set_markup('Not all available interfaces activated!\n\nThe interface '+device+' is present but offline. Please bring it up before running LTSP Manager if you want to use it. For LTSP.') dialog.connect("destroy", lambda w: self.win.set_sensitive(True)) resp = dialog.run() if resp: dialog.destroy() return True def get_keymaps(self): list = [] keyb_list = os.popen("grep xkb_keymap "+self.root+"/etc/X11/xkb/keymap/* | \ awk '{split($0, kb);printf \"%s\\n\", kb[2]}'|\ grep -v xkb_keymap|sort|uniq") list.append(keyb_list.read().split('\n')) for item in list[0][:-1]: self.wTree.get_widget("kbd_layout_combobox").append_text(str(item).strip('\"')) def get_kbmodels(self): list = [] newlist = [] keyb_list = os.popen("grep xkb_geometry "+self.root+"/etc/X11/xkb/geometry/*| \ awk '{split($0, kb);printf \"%s%s\\n\", kb[2],kb[3]}'") list.append(keyb_list.read().split('\n')) for item in list[0][:-1]: newlist.append(item.lstrip('xkb_geometry').rstrip('{').strip('\"')) newlist = self.unique(newlist) newlist.sort(lambda x, y: cmp(string.lower(x), string.lower(y))) for model in newlist: self.wTree.get_widget("kbd_model_combobox").append_text(model) def get_serial_protocols(self): modelist = os.popen("chroot "+self.root+" inputattach --help") for line in modelist.read().split('\n'): if line.lstrip().startswith('--'): self.wTree.get_widget("mouseproto_combobox").append_text(string.join(line.split()[2:]).rstrip()) def get_videodrivers(self): list = [] cardlist = os.popen("ls "+self.root+"/usr/lib/xorg/modules/drivers/*.so") list.append(cardlist.read().split('\n')) for item in list[0][:-1]: newitem = item.split('/')[-1].rstrip('_drv.so') self.wTree.get_widget("driver_combobox").append_text(newitem) def get_ip(self, ifname): s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) try: retval = socket.inet_ntoa(fcntl.ioctl( s.fileno(), 0x8915, # SIOCGIFADDR struct.pack('256s', ifname[:15]) )[20:24]) except: return False return retval def parse_dhcpd_conf(self): try: file = open('/etc/ltsp/dhcpd.conf', 'r') except: # make that an error dialog self.win.set_sensitive(False) dialog = gtk.MessageDialog(self.win, gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, gtk.MESSAGE_ERROR, gtk.BUTTONS_OK, None) dialog.set_markup('Can\'t open /etc/ltsp/dhcpd.conf !\n\nThe file /etc/ltsp/dhcpd.conf could not be opened, make sure the ltsp-server-standalone package is installed correctly. LTSP Manager will quit now.') dialog.connect("destroy", lambda w: self.win.set_sensitive(True)) resp = dialog.run() if resp: sys.exit(1) # read all the data for line in file.read().split('\n'): line = line.strip().lstrip('option ') if line.startswith('range'): self.range_from = line.strip('range').strip(';').split()[0] self.wTree.get_widget("range_from_entry").set_text(self.range_from) self.range_to = line.strip('range').strip(';').split()[1] self.wTree.get_widget("range_to_entry").set_text(self.range_to) elif line.startswith('domain-name '): self.domain_name = line.strip('domain-name ').strip(';').split()[0].strip('\"') self.wTree.get_widget("domain_entry").set_text(self.domain_name) elif line.startswith('domain-name-servers '): self.dns_server = line.strip('domain-name-servers ').strip(';').split()[0] self.wTree.get_widget("dns_entry").set_text(self.dns_server) elif line.startswith('broadcast-address '): self.broadcast = line.strip('broadcast-address ').strip(';').split()[0] self.wTree.get_widget("broadcast_entry").set_text(self.broadcast) elif line.startswith('routers '): self.routers = line.strip('routers ').strip(';').split()[0] self.wTree.get_widget("gateway_entry").set_text(self.routers) elif line.startswith('subnet-mask '): self.netmask = line.strip('subnet-mask ').strip(';').split()[0] self.wTree.get_widget("netmask_entry").set_text(self.netmask) net = self.range_from.rsplit(".", 1)[0]+'.' self.netlist = [net] match = False # determine the right interface and pre-select it iface = self.wTree.get_widget("iface_combobox") iface.append_text('none (old config)') for dev in self.devlist: iface.append_text(dev) self.netlist.append(self.get_ip(dev).rsplit(".", 1)[0]+'.') if self.get_ip(dev).startswith(net): iface.set_active(self.devlist.index(dev)+1) match = True if match == False: iface.set_active(0) # make that an error dialog self.win.set_sensitive(False) dialog = gtk.MessageDialog(self.win, gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, gtk.MESSAGE_ERROR, gtk.BUTTONS_OK, None) dialog.set_markup('No Matching Interfaces found !\n\nThere are no Network interfaces running that match the network configuration ('+net+'0) of the current LTSP DHCP configuration. Please adjust the DHCP settings to match a currently running interface with static IP address.') dialog.connect("destroy", lambda w: self.win.set_sensitive(True)) resp = dialog.run() if resp: self.wTree.get_widget("notebook1").set_current_page(3) dialog.destroy() else: iface.remove_text(0) self.netlist.reverse() self.netlist.pop() self.netlist.reverse() iface.connect("changed", lambda w: self.update_dhcp(iface)) def update_dhcp(self, iface): net = self.netlist[iface.get_active()] orig_net = [self.wTree.get_widget("range_from_entry").get_text().rsplit(".", 1)[1], \ self.wTree.get_widget("range_to_entry").get_text().rsplit(".", 1)[1], \ self.wTree.get_widget("broadcast_entry").get_text().rsplit(".", 1)[1], \ self.wTree.get_widget("gateway_entry").get_text().rsplit(".", 1)[1] ] self.wTree.get_widget("range_from_entry").set_text(net+orig_net[0]) self.wTree.get_widget("range_to_entry").set_text(net+orig_net[1]) self.wTree.get_widget("broadcast_entry").set_text(net+orig_net[2]) self.wTree.get_widget("gateway_entry").set_text(net+orig_net[3]) def compare_range(self, widget, event): base,range0 = self.wTree.get_widget("range_from_entry").get_text().rsplit(".", 1) range1 = self.wTree.get_widget("range_to_entry").get_text().rsplit(".", 1)[1] if int(range0) >= 255 or int(range1) >= 255: self.wTree.get_widget("range_from_entry").set_text(str(base)+'.253') self.wTree.get_widget("range_to_entry").set_text(str(base)+'.254') return if int(range0) >= int(range1): self.wTree.get_widget("range_to_entry").set_text(str(base)+'.'+str(int(range0)+1)) def unique(self,s): n = len(s) if n == 0: return [] u = {} try: for x in s: u[x] = 1 except TypeError: del u # move on to the next method else: return u.keys() try: t = list(s) t.sort() except TypeError: del t # move on to the next method else: assert n > 0 last = t[0] lasti = i = 1 while i < n: if t[i] != last: t[lasti] = last = t[i] lasti += 1 i += 1 return t[:lasti] # Brute force is all that's left. u = [] for x in s: if x not in u: u.append(x) return u def main(self): gtk.main() if __name__ == "__main__": base = LTSPManager() base.main()