Statistics
| Branch: | Revision:

root / shared-filer / grow @ bd924ffd

History | View | Annotate | Download (5.7 kB)

1 bd924ffd Dimitris Aragiorgis
#!/usr/bin/env python
2 bd924ffd Dimitris Aragiorgis
#
3 bd924ffd Dimitris Aragiorgis
# Copyright (C) 2012 Greek Research and Technology Network
4 bd924ffd Dimitris Aragiorgis
#
5 bd924ffd Dimitris Aragiorgis
# This program is free software; you can redistribute it and/or modify
6 bd924ffd Dimitris Aragiorgis
# it under the terms of the GNU General Public License as published by
7 bd924ffd Dimitris Aragiorgis
# the Free Software Foundation; either version 2 of the License, or
8 bd924ffd Dimitris Aragiorgis
# (at your option) any later version.
9 bd924ffd Dimitris Aragiorgis
#
10 bd924ffd Dimitris Aragiorgis
# This program is distributed in the hope that it will be useful, but
11 bd924ffd Dimitris Aragiorgis
# WITHOUT ANY WARRANTY; without even the implied warranty of
12 bd924ffd Dimitris Aragiorgis
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13 bd924ffd Dimitris Aragiorgis
# General Public License for more details.
14 bd924ffd Dimitris Aragiorgis
#
15 bd924ffd Dimitris Aragiorgis
# You should have received a copy of the GNU General Public License
16 bd924ffd Dimitris Aragiorgis
# along with this program; if not, write to the Free Software
17 bd924ffd Dimitris Aragiorgis
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18 bd924ffd Dimitris Aragiorgis
# 02110-1301, USA.
19 bd924ffd Dimitris Aragiorgis
20 bd924ffd Dimitris Aragiorgis
"""Grow an existing Image file
21 bd924ffd Dimitris Aragiorgis
22 bd924ffd Dimitris Aragiorgis
This program grows an existing Image file which resides under a
23 bd924ffd Dimitris Aragiorgis
shared directory.
24 bd924ffd Dimitris Aragiorgis
25 bd924ffd Dimitris Aragiorgis
It takes it's input from environment variables. Specifically the
26 bd924ffd Dimitris Aragiorgis
following variables should be present:
27 bd924ffd Dimitris Aragiorgis
28 bd924ffd Dimitris Aragiorgis
 - VOL_NAME: The name of the Image to grow
29 bd924ffd Dimitris Aragiorgis
 - VOL_SIZE: The current Image's size
30 bd924ffd Dimitris Aragiorgis
 - VOL_NEW_SIZE: The new size of the Image after it's grown
31 bd924ffd Dimitris Aragiorgis
32 bd924ffd Dimitris Aragiorgis
Returns 0 upon successful grow, 1 upon failure
33 bd924ffd Dimitris Aragiorgis
34 bd924ffd Dimitris Aragiorgis
"""
35 bd924ffd Dimitris Aragiorgis
36 bd924ffd Dimitris Aragiorgis
import os
37 bd924ffd Dimitris Aragiorgis
import sys
38 bd924ffd Dimitris Aragiorgis
39 bd924ffd Dimitris Aragiorgis
sys.path.append("/usr/share/ganeti/")
40 bd924ffd Dimitris Aragiorgis
41 bd924ffd Dimitris Aragiorgis
from ganeti import utils
42 bd924ffd Dimitris Aragiorgis
43 bd924ffd Dimitris Aragiorgis
44 bd924ffd Dimitris Aragiorgis
# Default shared directory
45 bd924ffd Dimitris Aragiorgis
SHARED_DIR = "/srv/ganeti/shared-file-storage"
46 bd924ffd Dimitris Aragiorgis
47 bd924ffd Dimitris Aragiorgis
48 bd924ffd Dimitris Aragiorgis
def ReadEnv():
49 bd924ffd Dimitris Aragiorgis
  """Read the mandatory enviromental variables
50 bd924ffd Dimitris Aragiorgis
51 bd924ffd Dimitris Aragiorgis
  """
52 bd924ffd Dimitris Aragiorgis
  name = os.getenv("VOL_NAME")
53 bd924ffd Dimitris Aragiorgis
  if name is None:
54 bd924ffd Dimitris Aragiorgis
    sys.stderr.write('The environment variable VOL_NAME is missing.\n')
55 bd924ffd Dimitris Aragiorgis
    return None
56 bd924ffd Dimitris Aragiorgis
  new_size = os.getenv("VOL_NEW_SIZE")
57 bd924ffd Dimitris Aragiorgis
  if new_size is None:
58 bd924ffd Dimitris Aragiorgis
    sys.stderr.write('The environment variable VOL_NEW_SIZE is missing.\n')
59 bd924ffd Dimitris Aragiorgis
    return None
60 bd924ffd Dimitris Aragiorgis
  shared_dir_param = os.getenv("EXTP_SHARED_DIR")
61 bd924ffd Dimitris Aragiorgis
  if shared_dir_param is not None:
62 bd924ffd Dimitris Aragiorgis
    sys.stderr.write('Found shared dir param, value: %s\n' % shared_dir_param)
63 bd924ffd Dimitris Aragiorgis
64 bd924ffd Dimitris Aragiorgis
  return (name, new_size, shared_dir_param)
65 bd924ffd Dimitris Aragiorgis
66 bd924ffd Dimitris Aragiorgis
67 bd924ffd Dimitris Aragiorgis
def _ParseLosetupOutput(output, filename):
68 bd924ffd Dimitris Aragiorgis
  """Parse the output of `losetup -j <filename>`
69 bd924ffd Dimitris Aragiorgis
70 bd924ffd Dimitris Aragiorgis
  This method parses the output of `losetup -j <filename>` and returns
71 bd924ffd Dimitris Aragiorgis
  the corresponding loop device path for this filename
72 bd924ffd Dimitris Aragiorgis
  (e.g. /dev/loop0)
73 bd924ffd Dimitris Aragiorgis
74 bd924ffd Dimitris Aragiorgis
  @type output: string
75 bd924ffd Dimitris Aragiorgis
  @param output: the whole output of `losetup -j filename`
76 bd924ffd Dimitris Aragiorgis
  @type filename: string
77 bd924ffd Dimitris Aragiorgis
  @param filename: the complete file path to the file we search for
78 bd924ffd Dimitris Aragiorgis
  @rtype: string or None
79 bd924ffd Dimitris Aragiorgis
  @return: loop device path if the file is losetup, else None
80 bd924ffd Dimitris Aragiorgis
81 bd924ffd Dimitris Aragiorgis
  """
82 bd924ffd Dimitris Aragiorgis
  # `losetup -j file1` output looks like this
83 bd924ffd Dimitris Aragiorgis
  #   /dev/loop0: [X]:Y (/path/to/file1)
84 bd924ffd Dimitris Aragiorgis
  # if the file has been losetup. If not there is no output.
85 bd924ffd Dimitris Aragiorgis
  # If the file has been losetup more than once, then there will be
86 bd924ffd Dimitris Aragiorgis
  # multiple lines like the one above.
87 bd924ffd Dimitris Aragiorgis
  #
88 bd924ffd Dimitris Aragiorgis
  # We assume the following format (space is the seperator):
89 bd924ffd Dimitris Aragiorgis
  # field0: field1 (field2)
90 bd924ffd Dimitris Aragiorgis
91 bd924ffd Dimitris Aragiorgis
  field0 = 0
92 bd924ffd Dimitris Aragiorgis
  field_sep = " "
93 bd924ffd Dimitris Aragiorgis
  
94 bd924ffd Dimitris Aragiorgis
  lines = output.splitlines()
95 bd924ffd Dimitris Aragiorgis
  splitted_lines = map(lambda l: l.split(field_sep), lines)
96 bd924ffd Dimitris Aragiorgis
97 bd924ffd Dimitris Aragiorgis
  # Check empty output. If empty, the file is not losetup
98 bd924ffd Dimitris Aragiorgis
  if not splitted_lines:
99 bd924ffd Dimitris Aragiorgis
    return None
100 bd924ffd Dimitris Aragiorgis
101 bd924ffd Dimitris Aragiorgis
  # Check if we have more than one lines in the output
102 bd924ffd Dimitris Aragiorgis
  if len(splitted_lines) > 1:
103 bd924ffd Dimitris Aragiorgis
    sys.stderr.write("The file %s is losetup more than once" % filename)
104 bd924ffd Dimitris Aragiorgis
    sys.exit(1)
105 bd924ffd Dimitris Aragiorgis
106 bd924ffd Dimitris Aragiorgis
  # The file is losetup only once
107 bd924ffd Dimitris Aragiorgis
  # Take field0, remove the ":" at the end and we have our path
108 bd924ffd Dimitris Aragiorgis
  dev_path = splitted_lines[0][field0].split(":")[0]
109 bd924ffd Dimitris Aragiorgis
110 bd924ffd Dimitris Aragiorgis
  return dev_path
111 bd924ffd Dimitris Aragiorgis
112 bd924ffd Dimitris Aragiorgis
113 bd924ffd Dimitris Aragiorgis
def main():
114 bd924ffd Dimitris Aragiorgis
  sys.stderr.write('Creation started: reading environment...\n')
115 bd924ffd Dimitris Aragiorgis
116 bd924ffd Dimitris Aragiorgis
  # Read environment.
117 bd924ffd Dimitris Aragiorgis
  env = ReadEnv()
118 bd924ffd Dimitris Aragiorgis
  if env is None:
119 bd924ffd Dimitris Aragiorgis
    sys.stderr.write('Wrong environment. Aborting\n')
120 bd924ffd Dimitris Aragiorgis
    return 1
121 bd924ffd Dimitris Aragiorgis
122 bd924ffd Dimitris Aragiorgis
  file_name, new_size, shared_dir_param = env
123 bd924ffd Dimitris Aragiorgis
124 bd924ffd Dimitris Aragiorgis
  if shared_dir_param is None:
125 bd924ffd Dimitris Aragiorgis
    shared_dir_param = SHARED_DIR
126 bd924ffd Dimitris Aragiorgis
127 bd924ffd Dimitris Aragiorgis
  file_path = utils.PathJoin(shared_dir_param, file_name)
128 bd924ffd Dimitris Aragiorgis
129 bd924ffd Dimitris Aragiorgis
  sys.stderr.write('Read environment successfully: file name: %s, '
130 bd924ffd Dimitris Aragiorgis
                   'new size: %sMB\n' % (file_path, new_size))
131 bd924ffd Dimitris Aragiorgis
132 bd924ffd Dimitris Aragiorgis
  # Check if the file exists.
133 bd924ffd Dimitris Aragiorgis
  if not os.path.exists(file_path):
134 bd924ffd Dimitris Aragiorgis
    sys.stderr.write("File %s does not exist. Aborting\n" % file_path)
135 bd924ffd Dimitris Aragiorgis
    return 1
136 bd924ffd Dimitris Aragiorgis
137 bd924ffd Dimitris Aragiorgis
  # Grow file.
138 bd924ffd Dimitris Aragiorgis
  try:
139 bd924ffd Dimitris Aragiorgis
    f = open(file_path, "a+")
140 bd924ffd Dimitris Aragiorgis
    f.truncate(int(new_size) * 1024 * 1024)
141 bd924ffd Dimitris Aragiorgis
    f.close()
142 bd924ffd Dimitris Aragiorgis
  except EnvironmentError, err:
143 bd924ffd Dimitris Aragiorgis
    sys.stderr.write('Error in file growth: %' % str(err))
144 bd924ffd Dimitris Aragiorgis
    return 1
145 bd924ffd Dimitris Aragiorgis
146 bd924ffd Dimitris Aragiorgis
  # Growth successful.
147 bd924ffd Dimitris Aragiorgis
  # Now the loop device needs to reread the size of the associated file.
148 bd924ffd Dimitris Aragiorgis
149 bd924ffd Dimitris Aragiorgis
  # Find out the loop device path first.
150 bd924ffd Dimitris Aragiorgis
  cmd1 = ["losetup", "-j", "%s" % file_path]
151 bd924ffd Dimitris Aragiorgis
  result = utils.RunCmd(cmd1)
152 bd924ffd Dimitris Aragiorgis
  if result.failed:
153 bd924ffd Dimitris Aragiorgis
    sys.stderr.write("losetup -j %s failed (%s): %s" %
154 bd924ffd Dimitris Aragiorgis
                     (dev_path, result.fail_reason, result.output))
155 bd924ffd Dimitris Aragiorgis
    return 1
156 bd924ffd Dimitris Aragiorgis
  else:
157 bd924ffd Dimitris Aragiorgis
    # Parse the result's output.
158 bd924ffd Dimitris Aragiorgis
    dev_path = _ParseLosetupOutput(result.output, file_path)
159 bd924ffd Dimitris Aragiorgis
160 bd924ffd Dimitris Aragiorgis
    if dev_path is None:
161 bd924ffd Dimitris Aragiorgis
      # The file is not attached. We should never get here during growth.
162 bd924ffd Dimitris Aragiorgis
      sys.stderr.write('File %s is not losetup during growth (%s): %s\n'
163 bd924ffd Dimitris Aragiorgis
                       'This should not happen. Aborting\n' %
164 bd924ffd Dimitris Aragiorgis
                        file_path, result.fail_reason, result.output)
165 bd924ffd Dimitris Aragiorgis
      return 1
166 bd924ffd Dimitris Aragiorgis
167 bd924ffd Dimitris Aragiorgis
    else:
168 bd924ffd Dimitris Aragiorgis
      # The file is losetup as expected. Reread size of file.
169 bd924ffd Dimitris Aragiorgis
      cmd2 = ["losetup", "-c", "%s" % dev_path]
170 bd924ffd Dimitris Aragiorgis
      result = utils.RunCmd(cmd2)
171 bd924ffd Dimitris Aragiorgis
      if result.failed:
172 bd924ffd Dimitris Aragiorgis
        sys.stderr.write('losetup -c %s failed (%s): %s' %
173 bd924ffd Dimitris Aragiorgis
                         (dev_path, result.fail_reason, result.output))
174 bd924ffd Dimitris Aragiorgis
        sys.stderr.write('You have to manually reread size of loop device `%s` '
175 bd924ffd Dimitris Aragiorgis
                         'since its associated file `%s` has grown\n' %
176 bd924ffd Dimitris Aragiorgis
                         (dev_path, file_path,
177 bd924ffd Dimitris Aragiorgis
                          result.fail_reason, result.output))
178 bd924ffd Dimitris Aragiorgis
        return 1
179 bd924ffd Dimitris Aragiorgis
180 bd924ffd Dimitris Aragiorgis
      # Growth and reread successful.
181 bd924ffd Dimitris Aragiorgis
      sys.stderr.write('Grow successful for file: %s\n' % file_path)
182 bd924ffd Dimitris Aragiorgis
      return 0
183 bd924ffd Dimitris Aragiorgis
184 bd924ffd Dimitris Aragiorgis
185 bd924ffd Dimitris Aragiorgis
if __name__ == "__main__":
186 bd924ffd Dimitris Aragiorgis
    sys.exit(main())