xentaur

view xentaur.py @ 50:ca80f73e403b

fix
author igor
date Thu Oct 25 18:02:18 2007 +0300 (2007-10-25)
parents 65e80fabc89c
children b9536e00100a
line source
1 #!/usr/bin/python
4 import sys,os,time
6 xentaur_path=os.environ['HOME']+"/xentaur"
8 sys.path.append('/etc/xen')
9 sys.path.append(xentaur_path)
11 network='snrs_ipsec_rsa_1'
12 domain='qua1'
13 from xendomain import *
15 bridges_turned_down=[]
17 from IPython.Shell import IPShellEmbed
20 screenrc=os.environ['HOME']+"/.screenrc_xentaur"
22 def run(program, *args):
23 pid = os.fork()
24 if not pid:
25 os.execvp(program, (program,) + args)
26 return os.wait()[0]
28 def run_command(line):
29 #cmds=line.split()
30 #run(cmds[0],*cmds[1:])
31 run("/bin/sh", "-c", line)
33 def run_command_return_stdout(line):
34 p = os.popen(line)
35 output = p.read()
36 p.close()
37 return output
39 ################################################################################
40 #Xentaur command-line commands
42 ## Start
44 def start_bridges():
45 unbound_bridges=set(bridges)-set(real_bridges)
46 create_unbound_bridges="\n".join(map(lambda x: "sudo brctl show | awk '{print $1}' | grep -qx "+x+" || sudo brctl addbr "+x, unbound_bridges))
47 create_unbound_bridges+="\n"+"\n".join(map(lambda x: "sudo brctl stp "+x+" off", unbound_bridges))
48 create_unbound_bridges+="\n"+"\n".join(map(lambda x: "sudo ip link set "+x+" up", unbound_bridges))
50 print """#!/bin/sh
51 # create unbound bridges
52 %(create_unbound_bridges)s
53 """ % {'create_unbound_bridges' : create_unbound_bridges}
55 def start_domain(domain):
56 print "sudo xm create "+xentaur_path+"/xendomain.py "+" domain="+domain+" network="+network+" && sleep 1 && sudo xm sched-credit -d $(sudo xm list | grep "+domain+" | awk '{print $2}') -c 10 && sleep 1"
58 def start_domains(doms=domains):
59 for domain in doms:
60 if not domain in real_nodes:
61 start_domain(domain)
63 def start_all():
64 graph()
65 screen()
66 start_bridges()
67 start_domains()
69 ## Stop
71 def stop_domain(domain,wait=0):
72 if wait:
73 print "sudo xm shutdown -w "+domain
74 else:
75 print "sudo xm shutdown "+domain
77 def stop_domains(doms=domains, wait=0):
78 for domain in doms:
79 if not domain in real_nodes:
80 stop_domain(domain,wait)
82 def stop_bridges():
83 ###FIXME###
84 return 0
86 def stop_all(wait=0):
87 stop_domains(domains, wait)
88 stop_bridges()
90 def restart_all():
91 stop_all(1)
92 start_all()
94 def screen():
95 N=1
96 screens=[]
97 for domain in domains:
98 screens.append("screen -t "+domain+" "+str(N)+" sh -c 'while true; do sudo xm console "+domain+" ; echo Retrying in 5 seconds...; sleep 5; done'")
99 N+=1
100 screenlist="\n".join(screens)
102 #
103 # Previous terminal acccess commands:
104 # ip="192.168.80."+str(200+N)
105 # screens.append("screen -t "+domain+" "+str(N)+" sh -c 'while true; do ssh root@"+ip+" ; done'")
106 #
108 hardstatus='hardstatus string "%{rk}Xentaur%{bk}@%H %{gk}%c %{yk}%d.%m %{wk}%?%-Lw%?%{bw}%n*%f%t%?(%u)%?%{wk}%?%+Lw%?"'
110 f=open(screenrc, "w");
111 f.write("""
112 hardstatus on
113 hardstatus alwayslastline
114 %s
116 screen -t console 0 bash
117 %s
118 """ % (hardstatus,screenlist))
119 f.close()
120 print "# GNU Screen config file is written to: %s" % screenrc
122 def graph_node(node):
123 i=0
124 domain_type={}
125 for domain in domains:
126 domain_type[domain]=domain_types[i]
127 i+=1
128 return node+" [label=\" "+node+"\",shapefile=\"shapes/all/"+domain_type[node]+".png\",fontcolor=black,fontsize=16]"
130 def graph_bridge(bridge):
131 if bridge in hidden_bridges:
132 return ""
133 if bridge in real_bridges:
134 return "%s [shape=none,shapefile=\"shapes/all/real_switch.png\"]" % (bridge)
135 elif bridge in bridges_turned_down:
136 return "%s [shape=none,shapefile=\"shapes/all/switch_turned_down.png\"]" % (bridge)
137 else:
138 return "%s [shape=none,shapefile=\"shapes/all/switch.png\"]" % (bridge)
141 def graph():
142 nodelist=""
143 bridgelist=""
144 linklist=""
145 physicallist=""
146 networklist=""
148 nodelist=";\n ".join(map(graph_node,nodes))
149 if nodelist: nodelist += ";"
151 bridgelist=";\n ".join(map(graph_bridge,bridges))
152 if bridgelist: bridgelist += ";"
154 links=[]
155 for host, bridges_raw in vbridges_table.iteritems():
156 i=0
157 for this_bridge in bridges_raw:
158 if this_bridge in hidden_bridges or not this_bridge:
159 continue
160 if not [ host, bridges_raw.index(this_bridge), this_bridge ] in temporary_links:
161 links.append(host+" -- "+this_bridge+" [taillabel=\"fa"+str(bridges_raw.index(this_bridge))+"/0\"]")
162 i+=1
164 for link in temporary_links:
165 links.append(link[0]+" -- "+link[2]+" [taillabel=\"fa"+str(link[1])+"/0\",color=blue,len=10,w=5,weight=5]")
167 for link in broken_links:
168 links.append(link[0]+" -- "+link[2]+" [taillabel=\"fa"+str(link[1])+"/0\",style=dashed]")
171 # bridge-bridge links
172 for host, bridges_raw in bridge_bridge_table.iteritems():
173 i=0
174 for this_bridge in bridges_raw:
175 if this_bridge in hidden_bridges or not this_bridge:
176 continue
177 if not [ host, bridges_raw.index(this_bridge), this_bridge ] in temporary_links:
178 links.append(host+" -- "+this_bridge)
179 i+=1
183 linklist=";\n ".join(links)
185 graph_dot = {
186 'nodelist' : nodelist,
187 'bridgelist' : bridgelist,
188 'linklist' : linklist,
189 'physicallist' : physicallist,
190 'networklist' : networklist,
191 }
193 f = open(network+".dot", "w");
194 f.write ("""
195 graph G {
196 edge [len=1.25];
197 splines=true;
198 // nodes
200 node [shape=plaintext,color=white,shapefile="shapes/cisco.bmp/router.png"];
201 %(nodelist)s
203 // bridges
205 node [shape=none,shapefile="shapes/all/switch.png"];
206 %(bridgelist)s
208 // physical
210 node [shape=rectangle,color=blue];
211 %(physicallist)s
213 // networks (not bridges, not physical)
214 node [shape=rectangle,color=green];
215 %(networklist)s
217 // links (between nodes and bridges)
218 %(linklist)s
220 };
221 """ % graph_dot)
222 f.close()
223 run_command("neato -Tpng -o %s.png %s.dot "%(network,network))
224 run_command("neato -Tjpg -o %s.jpg %s.dot "%(network,network))
225 run_command("neato -Tsvg -o %s.svg %s.dot "%(network,network))
226 print "# Network map is written to files: %s.{png,svg,jpg,dot}" % network
228 def autoredraw():
229 graph()
231 def shell():
232 autoredraw()
233 ipshell = IPShellEmbed()
234 ipshell()
237 def show_usage():
238 print """Usage:
239 xentaur <command> [<argument>]
241 Commands:
242 start-all -- start bridges and domains
243 start-domains -- start domains only
244 start-bridges -- start bridges only
245 stop-all -- stop bridges and domains
246 stop-domains -- stop domains only
247 stop-bridges -- stop bridges only (domains have to be stopped already)
248 restart-all -- restart bridges and domains
250 start <domain> -- start the <domain>
251 stop <domain> -- stop the <domain>
253 graph -- generate network scheme (result is in <network>.{png,jpg,svg})
254 screen -- generate GNU Screen config file (~/.screenrc_xentaur)
255 shell -- run Xentaur shell
257 """
259 def save():
260 print "network =", xen_config_name
261 print "domains =", domains
262 print "domain_types =", domain_types
263 print "bridges =", bridges
264 print "vbridges_table =", vbridges_table
265 print "hidden_bridges =", hidden_bridges
266 print "broken_links =", broken_links
267 print "temporary_links =", temporary_links
268 print "bridges_turned_down =", bridges_turned_down
270 #-----------------------------------------------------------------------
271 # CLASSES
273 class Bridge:
274 def __init__ (self,name):
275 self.name=name
276 def up(self):
277 bridge_up(self.name)
278 def down(self):
279 bridge_down(self.name)
280 def show(self):
281 show_bridge(self.name)
282 def dump_start(self,filter=""):
283 dump_start(self.name,filter)
286 class Domain:
287 def __init__ (self,name):
288 self.name=name
289 def start(self):
290 return ""
291 def stop(self):
292 return ""
293 def start_commandline(self):
294 return ""
295 def graphviz(self):
296 return ""
297 def get_domain_id(self):
298 return get_domain_id(self.name)
300 #-----------------------------------------------------------------------
301 # DOMAINS
303 def get_domain_id(domain):
304 return run_command_return_stdout("sudo xm list | awk '{if ($1 == \"'%s'\") print $2}'" % domain).rstrip("\n")
307 #-----------------------------------------------------------------------
308 # BRIDGES and IFACES
310 def bridge_down(bridge):
311 """
312 Turn the bridge <bridge> down
313 """
314 if bridge in real_bridges:
315 print "Bridge %s is a real bridge" % (bridge)
316 return -1
317 if bridge in bridges_turned_down:
318 print "Bridge %s is turned down already" % (bridge)
319 else:
320 bridges_turned_down.append(bridge)
321 run_command("sudo ip link set %s down" % bridge)
322 autoredraw()
324 def bridge_up(bridge):
325 """
326 Turn the bridge <bridge> up
327 """
328 if bridge in real_bridges:
329 print "Bridge %s is a real bridge" % (bridge)
330 return -1
331 if not (bridge in bridges_turned_down):
332 print "Bridge %s is turned up already" % (bridge)
333 else:
334 bridges_turned_down.remove(bridge)
335 run_command("sudo ip link set %s up" % bridge)
336 autoredraw()
338 def show_bridge(bridge):
339 """
340 Show the state of the bridge <bridge>
341 """
342 if bridge in real_bridges:
343 print "Bridge %s is a real bridge" % (bridge)
344 return -1
345 run_command("sudo ip link show %s" % bridge)
348 def int_disconnect(domain, int_number):
349 """
350 Disconnect the interface with the number <int_number>
351 of the domain <domain> from the bridge to which
352 it is connected
353 """
354 dom_id=get_domain_id(domain)
355 bridge=vbridges_table[domain][int_number]
356 if not bridge:
357 print "Interface %s of the %s domain is not connected" % (int_number, domain)
358 return 1
359 run_command("sudo brctl delif %s vif%s.%s" % (bridge, dom_id, int_number))
360 vbridges_table[domain][int_number]=''
361 if [ domain, int_number, bridge ] in temporary_links:
362 temporary_links.remove([ domain, int_number, bridge ])
363 else:
364 broken_links.append([ domain, int_number, bridge ])
365 autoredraw()
367 def int_connect(domain, int_number, bridge):
368 """
369 Connect the interface with the number <int_number>
370 of the domain <domain> to the bridge <bridge>
371 """
372 if bridge in real_bridges:
373 print "Bridge %s is a real bridge" % (bridge)
374 return -1
376 dom_id=get_domain_id(domain)
377 if vbridges_table[domain][int_number]:
378 print "Interface %s of the %s domain is connected already to the %s bridge" % (int_number, domain, vbridges_table[domain][int_number])
379 return 1
380 run_command("sudo brctl addif %s vif%s.%s" % (bridge, dom_id, int_number))
381 vbridges_table[domain][int_number]=bridge
382 if [ domain, int_number, bridge ] in broken_links:
383 broken_links.remove([ domain, int_number, bridge ])
384 else:
385 temporary_links.append([ domain, int_number, bridge ])
386 autoredraw()
388 def int_reconnect(domain, int_number, bridge):
389 """
390 Reconnect the interface with the number <int_number>
391 of the domain <domain> from the bridge to which
392 it is connected to the bridge <bridge>
393 """
394 if bridge in real_bridges:
395 print "Bridge %s is a real bridge" % (bridge)
396 return -1
398 int_disconnect(domain, int_number)
399 int_connect(domain, int_number, bridge)
401 def show_int(domain, int_number):
402 """
403 Show information about the interface <int_nuber>
404 of the domain <domain>
405 """
406 return vbridges_table[domain][int_number]
409 def dump_start(bridge, filter=""):
410 if bridge in real_bridges:
411 print "Bridge %s is a real bridge" % (bridge)
412 return -1
413 try:
414 print "Writing dump... (press Ctrl-C to stop)"
415 run_command("sudo tcpdump -w xentaur.dump -i %s %s > /dev/null 2>&1 " % (bridge,filter))
416 except:
417 print "Done.\n Dump is written to xentaur.dump"
418 return 0
420 def dump_stop():
421 return 0
424 #-----------------------------------------------------------------------
425 # CONFIGURATION TEMPLATES
428 def configure_ip_addresses(doms=domains):
430 cisco_set_ip_on_int="""
431 \n\n\n
432 int fa%s/0
433 no ip address
434 ip address %s 255.255.255.0
435 no shutdown
436 exit
437 """
439 quagga_set_ip_on_int="""
440 int eth%s
441 no ip address
442 ip address %s/24
443 no shutdown
444 exit
445 """
447 for dom in doms:
448 i=domains.index(dom)+1
449 if domain_types[domains.index(dom)] == 'quagga':
450 command = quagga_set_ip_on_int
451 write_to(i,"\nconf t\n")
452 j=0
453 for br in vbridges_table[dom]:
454 write_to(i,command % (j, "192.168.%s.%s"%(bridges.index(br)+1,i)))
455 j+=1
456 write_to(i,"\nend\n")
457 else:
458 command = cisco_set_ip_on_int
459 write_to(i,"\nena\nconf t\n")
460 j=0
461 for br in vbridges_table[dom]:
462 write_to(i,command % (j, "192.168.%s.%s"%(bridges.index(br)+1,i)))
463 j+=1
464 write_to(i,"\nend\n")
465 return 0
467 def configure_no_ip_addresses(doms=domains):
469 cisco_set_ip_on_int="""
470 \n\n\n
471 int fa%s/0
472 no ip address %s 255.255.255.0
473 exit
474 """
476 quagga_set_ip_on_int="""
477 int eth%s
478 no ip address %s/24
479 exit
480 """
482 for dom in doms:
483 i=domains.index(dom)+1
484 if domain_types[domains.index(dom)] == 'quagga':
485 command = quagga_set_ip_on_int
486 write_to(i,"\nconf t\n")
487 j=0
488 for br in vbridges_table[dom]:
489 write_to(i,command % (j, "192.168.%s.%s"%(bridges.index(br)+1,i)))
490 j+=1
491 write_to(i,"\nend\n")
492 else:
493 command = cisco_set_ip_on_int
494 write_to(i,"\nena\nconf t\n")
495 j=0
496 for br in vbridges_table[dom]:
497 write_to(i,command % (j, "192.168.%s.%s"%(bridges.index(br)+1,i)))
498 j+=1
499 write_to(i,"\nend\n")
500 return 0
502 def configure_ospf(doms=domains):
503 for dom in doms:
504 if domain_types[domains.index(dom)] == 'quagga':
505 write_to(dom,"\n\nconf t\nrouter ospf\nnetwork 192.168.0.0/16 area 0\nend\n")
506 else:
507 write_to(dom,"\n\nena\nconf t\nrouter ospf 1\nnetwork 192.168.0.0 0.0.255.255 area 0\nend\n")
508 return 0
510 def configure_hostname(doms=domains):
511 for dom in doms:
512 if domain_types[domains.index(dom)] == 'quagga':
513 write_to(dom,"\n\nconf t\nhostname %s\nend\n" % dom)
514 else:
515 write_to(dom,"\n\nena\nconf t\nhostname %s\nend\n" % dom)
516 return 0
518 def configure_logging_synchronous(doms=domains):
519 for dom in domains:
520 if domain_types[domains.index(dom)] == 'quagga':
521 0
522 else:
523 write_to(dom,"\n\nena\nconf t\nline console 0\nlogging synchronous\nend\n")
524 return 0
526 def configure_save(doms=domains):
527 write_to(doms,"\nwr\n")
529 def configure_root(doms=domains):
530 write_to(doms,"root\n")
532 #-----------------------------------------------------------------------
535 def add_domain(name,type):
536 domains.append(name)
537 domain_types.append(type)
539 def brake_link(domain,bridge):
540 broken_links.append([domain,bridge])
542 wt_timeout=0.5
543 def write_to(screen,string,return_to_screen=""):
544 """
545 write_to(screen,string):
547 Type *string* to the specified screen(s).
548 Screen may be specified with the number *screen*,
549 with array of numbers,
550 with array of names.
552 """
553 screen_numbers=[] # number of the screens to write to
554 if type(screen) == list:
555 screen_numbers=map(lambda x: domains.index(x)+1, screen)
556 elif type(screen) == int:
557 screen_numbers=[screen]
558 else:
559 screen_numbers=[domains.index(screen)+1]
561 for screen_number in screen_numbers:
562 run_command("screen -X select "+str(screen_number))
563 time.sleep(wt_timeout)
564 for line in string.splitlines():
565 f=open('/tmp/xentaurbuf', 'w')
566 f.write(line+"\n")
567 f.close()
568 run_command("screen -X readreg p /tmp/xentaurbuf")
569 time.sleep(wt_timeout)
570 run_command("nohup screen -X paste p >& /dev/null")
571 time.sleep(wt_timeout)
573 if return_to_screen != "":
574 run_command("screen -X select %s" % (return_to_screen))
575 time.sleep(wt_timeout)
577 def filter_by_type(doms,type):
578 """
579 filter_by_type(doms,type)
581 Return only domains of *doms* that have specified *type*
582 """
583 return filter(lambda x: domain_types[domains.index(x)]==type,domains)
585 #-----------------------------------------------------------------------
587 cisco_fa01_up="""
588 ena
589 conf t
590 int fa0/0
591 duplex half
592 no shutdown
593 exit
594 int fa1/0
595 duplex half
596 no shutdown
597 exit
598 exit
599 exit
600 """
602 cisco_set_ip_on_int="""
603 interface fa%s/0
604 no ip address
605 ip address %s 255.255.255.0
606 exit
607 """
609 nodes=domains
611 if len(sys.argv) == 2:
612 if sys.argv[1] == 'start-all':
613 start_all()
614 elif sys.argv[1] == 'start-domains':
615 start_domains()
616 elif sys.argv[1] == 'start-bridges':
617 start_bridges()
618 elif sys.argv[1] == 'stop-all':
619 stop_all()
620 elif sys.argv[1] == 'stop-domains':
621 stop_domains()
622 elif sys.argv[1] == 'stop-bridges':
623 stop_bridges()
624 elif sys.argv[1] == 'restart-all':
625 restart_all()
626 elif sys.argv[1] == 'screen':
627 screen()
628 elif sys.argv[1] == 'graph':
629 graph()
630 elif sys.argv[1] == 'shell':
631 shell()
632 else:
633 show_usage()
634 sys.exit(1)
635 elif len(sys.argv) == 3:
636 if sys.argv[1] == 'start':
637 start_domain(sys.argv[2])
638 elif sys.argv[1] == 'stop':
639 stop_domain(sys.argv[2])
640 elif sys.argv[1] == 'restart':
641 stop_domain(sys.argv[2])
642 start_domain(sys.argv[2])
643 else:
644 show_usage()
645 sys.exit(1)
646 else:
647 show_usage()
648 sys.exit(1)
650 sys.exit(0)