fix peer.c pidfile handling on error, plus archipelagos control file changes
[archipelago] / xseg / archipelagos
1 #!/usr/bin/env python
2 #
3 # archipelagos tool
4
5 import os, sys, subprocess, argparse, time, psutil, signal
6 from subprocess import call, check_call
7
8 BIN_PATH="/usr/bin"
9 MAPPER="mt-mapperd"
10 VLMC="st-vlmcd"
11 BLOCKER="pfiled"
12 PIDFILE_PATH="/var/run/archipelagos"
13 CHARDEV_NAME="/dev/segdev"
14 CHARDEV_MAJOR="60"
15 CHARDEV_MINOR="0"
16
17 try:
18     execfile(os.path.expanduser("/etc/default/archipelagos"), globals())
19 except:
20     pass
21
22 #FIXME check defaults
23 peer_blockerb = [BLOCKER, ["-p" , str(BPORT), "-g", str(SPEC), "-n", str(NR_OPS),
24         str(PITHOS), str(IMAGES), "-d", "--pidfile", os.path.join(PIDFILE_PATH, "blockerd.pid")], "blockerb"]
25 peer_blockerm = [BLOCKER, ["-p" , str(MBPORT), "-g", str(SPEC), "-n", str(NR_OPS),
26         str(PITHOSMAPS), str(MAPS), "-d", "--pidfile", os.path.join(PIDFILE_PATH, "blockerm.pid")], "blockerm" ]
27 peer_vlmcd = [VLMC, ["-t" , "1", "-sp",  str(VPORT_START), "-ep", str(VPORT_END), 
28         "-g", str(SPEC), "-n", str(NR_OPS), "-bp", str(BPORT), "-mp", str(MPORT),
29         "-d", "--pidfile", os.path.join(PIDFILE_PATH, "vlmcd.pid")], "vlmcd"]
30 peer_mapperd = [MAPPER, ["-t" , "1", "-p",  str(MPORT), "-mbp", str(MBPORT),
31         "-g", str(SPEC), "-n", str(NR_OPS), "-bp", str(BPORT), "-d", "--pidfile",
32         os.path.join(PIDFILE_PATH, "mapper.pid")], "mapper"]
33
34 #peers = [peer_blockerb, peer_blockerm, peer_vlmcd, peer_mapperd]
35 peers = [peer_vlmcd, peer_mapperd]
36 modules = ["xseg", "segdev", "xseg_posix", "xseg_pthread", "xseg_segdev"]
37 xsegbd = "xsegbd"
38     
39 def exclusive(fn):
40     def exclusive_args(args):
41         file = "/tmp/vlmc_map.lock"
42         while True:
43             try:
44                 fd = os.open(file, os.O_CREAT|os.O_EXCL|os.O_WRONLY)
45                 break;
46             except Exception, reason:
47                 print >> sys.stderr, reason
48                 time.sleep(0.05)
49         try:
50             fn(args)
51         finally:
52             os.close(fd)
53             os.unlink(file)
54
55     return exclusive_args
56
57 @exclusive
58 def vlmc_showmapped(args):
59     print "id\tpool\timage\tsnap\tdevice"
60     try:
61         for f in os.listdir(XSEGBD_SYSFS + "devices/"):
62             d_id = open(XSEGBD_SYSFS + "devices/" + f + "/id").read().strip()
63             target = open(XSEGBD_SYSFS + "devices/"+ f + "/target").read().strip()
64
65             print "%s\t%s\t%s\t%s\t%s" % (d_id, '-', target, '-', DEVICE_PREFIX +
66             d_id)
67     except Exception, reason:
68         print >> sys.stderr, reason
69         sys.exit(-1)
70
71 def loadrc(rc):
72     #FIXME
73     #check config file sanity
74     try:
75         if rc == None:
76             execfile(os.path.expanduser("/etc/default/archipelagos"), globals())
77         else:
78             execfile(rc, globals())
79     except:
80         pass
81
82 def loaded_modules():
83     lines = open("/proc/modules").read().split("\n")
84     modules = [f.split(" ")[0] for f in lines]
85     return modules
86
87 def load_module(name):
88     modules = loaded_modules()
89     if name in modules:
90         return 0
91     cmd = ["modprobe -v %s" % name]
92     print cmd
93     try:
94         check_call(cmd, shell=True);
95     except Exception:
96             sys.stderr.write("Module %s failed to load. \n" % name)
97             return -1
98     return 0
99
100 def unload_module(name):
101     modules = loaded_modules()
102     if name not in modules:
103         return 0
104     cmd = ["modprobe -rv %s" % name]
105     print cmd
106     try:
107         check_call(cmd, shell=True);
108     except Exception:
109             sys.stderr.write("Module %s failed to unload. \n" % name)
110             return -1
111     return 0
112
113 def create_segment():
114     #fixme blocking....
115     cmd = ["xseg", str(SPEC), "create"]
116     try:
117         check_call(cmd, shell=False);
118     except Exception:
119             sys.stderr.write("Cannot create segment. \n")
120             return -1
121     return 0
122
123 def destroy_segment():
124     #fixme blocking....
125     cmd = ["xseg", str(SPEC), "destroy"]
126     try:
127         check_call(cmd, shell=False);
128     except Exception:
129             sys.stderr.write("Cannot destroy segment. \n")
130             return 0
131     return 0
132
133 def check_running(name, pid = -1):
134     for p in psutil.process_iter():
135         if p.name == name:
136             if pid != -1:
137                 if pid != p.pid:
138                     return -1
139             else:
140                 return pid
141     return -1
142
143 def check_pidfile(name):
144     pidfile = os.path.join(PIDFILE_PATH, name + ".pid")
145     pf = None
146     try:
147         pf = open(pidfile, "r")
148         pid = int(pf.read())
149         pf.close()
150     except:
151         if pf:
152             pf.close()
153         return -1
154
155     return pid
156
157 def start_peer(peer):
158     cmd = [peer[0]] + peer[1]
159     try:
160         check_call(cmd, shell=False);
161     except Exception:
162         sys.stderr.write("Peer %s start failed.\n" % peer[0])
163         return -1
164     return 0
165
166 def stop_peer(peer):
167     pid = check_pidfile(peer[2])
168     if pid < 0:
169         print " process not running"
170         return -1
171
172     os.kill(pid, signal.SIGTERM)
173     i = 0
174     while check_running(peer[0], pid) > 0:
175         time.sleep(0.1)
176         i += 1
177         if i > 100:
178             print "process did not die in 10 secs"
179             return -1
180     return 0
181
182 def make_segdev():
183     try:
184         os.stat(str(CHARDEV_NAME))
185         return -2
186     except:
187         pass
188     cmd = ["mknod", str(CHARDEV_NAME), "c", str(CHARDEV_MAJOR), str(CHARDEV_MINOR)]
189     print cmd
190     try:
191         check_call(cmd, shell=False);
192     except Exception:
193         sys.stderr.write("Segdev %s device creation failed. \n")
194         return -1
195     return 0
196
197 def remove_segdev():
198     try:
199         os.stat(str(CHARDEV_NAME))
200     except:
201         return -2
202     try:
203         os.unlink(str(CHARDEV_NAME))
204     except:
205         sys.stderr.write("Segdev %s device removal failed. \n")
206         return -1
207
208
209 def start(args):
210     
211     
212     #if sth running or loaded 
213     # return -1
214
215     for m in modules:
216         if load_module(m) < 0:
217             stop(args)
218             return -1
219     time.sleep(0.5)
220
221     if make_segdev() < 0:
222         stop(args)
223         return -1
224     
225     time.sleep(0.5)
226     
227     if create_segment() < 0:
228         stop(args)
229         return -1
230     
231     time.sleep(0.5)
232     
233     for p in peers:
234         if start_peer(p) < 0:
235             stop(args)
236             return -1
237
238
239     if load_module(xsegbd) < 0:
240         stop(args)
241         return -1
242     return 0
243
244 def stop(args):
245     #check devices
246     if unload_module(xsegbd):
247         return -1
248     
249     for p in reversed(peers):
250         stop_peer(p)
251
252
253     #destroy segment with timeout
254 #    if destroy_segment() < 0:
255 #       return -1
256
257     remove_segdev()
258     
259     for m in reversed(modules):
260         unload_module(m)
261
262
263 if __name__ == "__main__":
264     # parse arguments and discpatch to the correct func
265     parser = argparse.ArgumentParser(description='vlmc tool')
266     parser.add_argument('-c', '--config', type=str, nargs='?', help='config file')
267     subparsers = parser.add_subparsers()
268
269     start_parser = subparsers.add_parser('start', help='Resize volume')
270     start_parser.set_defaults(func=start)
271     
272     start_parser = subparsers.add_parser('stop', help='Resize volume')
273     start_parser.set_defaults(func=stop)
274
275     args = parser.parse_args()
276     args.func(args)