add license headers
[archipelago] / xseg / tools / ext_scripts / vlmc_wrapper.py
1 #!/usr/bin/env python
2 #
3 # Copyright (C) 2012 Greek Research and Technology Network
4 #
5 # This program is free software; you can redistribute it and/or modify
6 # it under the terms of the GNU General Public License as published by
7 # the Free Software Foundation; either version 2 of the License, or
8 # (at your option) any later version.
9 #
10 # This program is distributed in the hope that it will be useful, but
11 # WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13 # General Public License for more details.
14 #
15 # You should have received a copy of the GNU General Public License
16 # along with this program; if not, write to the Free Software
17 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18 # 02110-1301, USA.
19
20 """ vlmc provider wrapper-script for ganeti extstorage disk template
21
22 The script takes it's input from environment variables. Specifically the
23 following variables should be present:
24
25  - VOL_NAME: The name of the new Image file
26  - VOL_SIZE: The size of the new Image (in megabytes)
27
28 The following variables are optional:
29
30  - EXTP_ORIGIN: The name of the Image file to snapshot
31
32 The code branches to the correct function, depending on the name (sys.argv[0])
33 of the executed script (attach, create, etc).
34
35 Returns O after successfull completion, 1 on failure
36
37 """
38
39 import os
40 import sys
41
42 from ganeti import utils
43
44
45 def ReadEnv():
46   """Read the enviromental variables
47   """
48
49   name = os.getenv("VOL_NAME")
50   if name is None:
51     sys.stderr.write('The environment variable VOL_NAME is missing.\n')
52     return None
53
54   size = os.getenv("VOL_SIZE")
55 #  if size is None:
56 #    sys.stderr.write('The environment variable VOL_SIZE is missing.\n')
57 #    return None
58
59   origin = os.getenv("EXTP_ORIGIN")
60
61   return (name, size, origin)
62
63 def create(env):
64   """Create a new vlmc Image
65   """
66   sys.stderr.write('Creation started...\n')
67
68   name, size, origin = env
69
70   cmd = ["vlmc", "create", "%s" % name, "--size", "%s" % size]
71   if origin:
72      cmd.extend(["--snap", origin])
73
74   sys.stderr.write('Before RunCmd')
75   result = utils.RunCmd(cmd)
76   sys.stderr.write('After RunCmd')
77
78   if result.failed:
79     sys.stderr.write('vlmc creation failed (%s): %s\n' %
80                      (result.fail_reason, result.output))
81     return 1 
82
83   return 0
84
85 def _ParseVlmcShowmappedOutput(output, volume_name):
86   """Parse the output of `vlmc showmapped'.
87
88   This method parses the output of `vlmc showmapped' and returns
89   the vlmc block device path (e.g. /dev/xsegbd0) that matches the
90   given vlmc volume.
91
92   """
93   allfields = 5
94   volumefield = 2
95   devicefield = 4
96
97   field_sep = "\t"
98
99   lines = output.splitlines()
100   splitted_lines = map(lambda l: l.split(field_sep), lines)
101
102   # Check empty output.
103   if not splitted_lines:
104     sys.stderr.write("vlmc showmapped returned empty output")
105     sys.exit(1)
106
107   # Check showmapped header line, to determine number of fields.
108   field_cnt = len(splitted_lines[0])
109   if field_cnt != allfields:
110     sys.stderr.write("Cannot parse vlmc showmapped output because its format"
111                 " seems to have changed; expected %s fields, found %s" % 
112                 (allfields, field_cnt)
113     sys.exit(1)
114
115   matched_lines = \
116     filter(lambda l: len(l) == allfields and l[volumefield] == volume_name,
117            splitted_lines)
118
119   if len(matched_lines) > 1:
120     sys.stderr.write("The vlmc volume %s is mapped more than once."
121                 " This shouldn't happen, try to unmap the extra"
122                 " devices manually." % volume_name)
123     sys.exit(1) 
124
125   if matched_lines:
126     # vlmc block device found. Return it.
127     dev = matched_lines[0][devicefield]
128     return dev
129
130   # The given volume is not mapped.
131   return None
132
133 def attach(env):
134   """Map an existing vlmc Image to a block device
135
136   This function maps an existing vlmc Image to a block device
137   e.g. /dev/xsegbd{X} and returns the device path. If the mapping
138   already exists, it returns the corresponding device path.
139   """
140
141   name, _, _ = env
142
143   # Check if the mapping already exists
144   cmd = ["vlmc", "showmapped"]
145   result = utils.RunCmd(cmd)
146   if result.failed:
147     sys.stderr.write("vlmc showmapped failed (%s): %s" %
148                      (result.fail_reason, result.output))
149     return 1
150
151   dev = _ParseVlmcShowmappedOutput(result.output, name)
152   if dev:
153     # The mapping exists. Return it.
154     sys.stdout.write("%s" % str(dev))
155     return 0
156
157   # The mapping doesn't exist. Create it.
158   map_cmd = ["vlmc", "map", name]
159   result = utils.RunCmd(map_cmd)
160   if result.failed:
161     sys.stderr.write("vlmc map failed (%s): %s" %
162                 (result.fail_reason, result.output))
163     return 1
164
165   # Find the corresponding vlmc device.
166   showmap_cmd = ["vlmc", "showmapped"]
167   result = utils.RunCmd(showmap_cmd)
168   if result.failed:
169     sys.stderr.write("vlmc map succeeded, but showmapped failed (%s): %s" %
170                 (result.fail_reason, result.output))
171     return 1
172
173   dev = _ParseVlmcShowmappedOutput(result.output, name)
174
175   if not dev:
176     sys.stderr.write("vlmc map succeeded, but could not find the vlmc block"
177                 " device in output of showmapped, for volume: %s" % name)
178
179   # The device was successfully mapped. Return it.
180   sys.stdout.write("%s" % str(dev))
181   return 0
182
183 def detach(env):
184   """Unmap a vlmc device from the Image it is mapped to
185
186   This function unmaps an vlmc device from the Image it is mapped to.
187   It is idempotent if the mapping doesn't exist at all.
188   """
189   name, _, _ = env
190
191   # Check if the mapping already exists
192   cmd = ["vlmc", "showmapped"]
193   result = utils.RunCmd(cmd)
194   if result.failed:
195     sys.stderr.write("vlmc showmapped failed (%s): %s" %
196                      (result.fail_reason, result.output))
197     return 1
198
199   dev = _ParseVlmcShowmappedOutput(result.output, name)
200
201   if dev:
202     # The mapping exists. Unmap the vlmc device.
203     unmap_cmd = ["vlmc", "unmap", "%s" % dev]
204     result = utils.RunCmd(unmap_cmd)
205     if result.failed:
206       sys.stderr.write("vlmc unmap failed (%s): %s",
207                   result.fail_reason, result.output)
208
209   return 0
210
211 def grow(env):
212   """Grow an existing vlmc Image
213   """
214   name, size, _ = env
215
216   cmd = ["vlmc", "resize", "%s" % name, "--size", "%s" % size]
217
218   result = utils.RunCmd(cmd)
219   if result.failed:
220     sys.stderr.write('vlmc resize failed (%s): %s\n' %
221                      (result.fail_reason, result.output))
222     return 1
223
224   return 0
225
226 def remove(env):
227   """ Delete a vlmc Image
228   """
229
230   name, _, _ = env
231
232   cmd = ["vlmc", "rm", "%s" % name]
233
234   result = utils.RunCmd(cmd)
235   if result.failed:
236     sys.stderr.write("Can't remove Image %s from cluster with vlmc rm: "
237                      "%s - %s" % 
238                      (name, result.fail_reason, result.output))
239     return 1
240
241   return 0
242
243 def verify(env):
244   return 0
245
246 def main():
247   env = ReadEnv()
248   if env is None:
249     sys.stderr.write("Wrong environment. Aborting...\n")
250     return 1
251
252   try:
253     return {
254       'attach': attach,
255       'create': create,
256       'detach': detach,
257       'grow'  : grow,
258       'remove': remove,
259       'verify': verify
260     }[os.path.basename(sys.argv[0])](env)
261   except:
262     sys.stderr.write("Op not supported")
263     return 1
264
265 if __name__ == "__main__":
266     sys.exit(main())