Statistics
| Branch: | Tag: | Revision:

root / lib / storage / extstorage.py @ ab0c6a39

History | View | Annotate | Download (15.3 kB)

1 87e9bdb7 Ilias Tsitsimpis
#
2 87e9bdb7 Ilias Tsitsimpis
#
3 87e9bdb7 Ilias Tsitsimpis
4 87e9bdb7 Ilias Tsitsimpis
# Copyright (C) 2014 Google Inc.
5 87e9bdb7 Ilias Tsitsimpis
#
6 87e9bdb7 Ilias Tsitsimpis
# This program is free software; you can redistribute it and/or modify
7 87e9bdb7 Ilias Tsitsimpis
# it under the terms of the GNU General Public License as published by
8 87e9bdb7 Ilias Tsitsimpis
# the Free Software Foundation; either version 2 of the License, or
9 87e9bdb7 Ilias Tsitsimpis
# (at your option) any later version.
10 87e9bdb7 Ilias Tsitsimpis
#
11 87e9bdb7 Ilias Tsitsimpis
# This program is distributed in the hope that it will be useful, but
12 87e9bdb7 Ilias Tsitsimpis
# WITHOUT ANY WARRANTY; without even the implied warranty of
13 87e9bdb7 Ilias Tsitsimpis
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 87e9bdb7 Ilias Tsitsimpis
# General Public License for more details.
15 87e9bdb7 Ilias Tsitsimpis
#
16 87e9bdb7 Ilias Tsitsimpis
# You should have received a copy of the GNU General Public License
17 87e9bdb7 Ilias Tsitsimpis
# along with this program; if not, write to the Free Software
18 87e9bdb7 Ilias Tsitsimpis
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 87e9bdb7 Ilias Tsitsimpis
# 02110-1301, USA.
20 87e9bdb7 Ilias Tsitsimpis
21 87e9bdb7 Ilias Tsitsimpis
22 87e9bdb7 Ilias Tsitsimpis
"""ExtStorage Interface related functionality
23 87e9bdb7 Ilias Tsitsimpis

24 87e9bdb7 Ilias Tsitsimpis
"""
25 87e9bdb7 Ilias Tsitsimpis
26 87e9bdb7 Ilias Tsitsimpis
import re
27 87e9bdb7 Ilias Tsitsimpis
import stat
28 87e9bdb7 Ilias Tsitsimpis
import os
29 87e9bdb7 Ilias Tsitsimpis
import logging
30 87e9bdb7 Ilias Tsitsimpis
31 87e9bdb7 Ilias Tsitsimpis
from ganeti import utils
32 87e9bdb7 Ilias Tsitsimpis
from ganeti import errors
33 87e9bdb7 Ilias Tsitsimpis
from ganeti import constants
34 87e9bdb7 Ilias Tsitsimpis
from ganeti import objects
35 87e9bdb7 Ilias Tsitsimpis
from ganeti import pathutils
36 87e9bdb7 Ilias Tsitsimpis
from ganeti.storage import base
37 87e9bdb7 Ilias Tsitsimpis
38 87e9bdb7 Ilias Tsitsimpis
39 87e9bdb7 Ilias Tsitsimpis
class ExtStorageDevice(base.BlockDev):
40 87e9bdb7 Ilias Tsitsimpis
  """A block device provided by an ExtStorage Provider.
41 87e9bdb7 Ilias Tsitsimpis

42 87e9bdb7 Ilias Tsitsimpis
  This class implements the External Storage Interface, which means
43 87e9bdb7 Ilias Tsitsimpis
  handling of the externally provided block devices.
44 87e9bdb7 Ilias Tsitsimpis

45 87e9bdb7 Ilias Tsitsimpis
  """
46 87e9bdb7 Ilias Tsitsimpis
  def __init__(self, unique_id, children, size, params, dyn_params, *args):
47 87e9bdb7 Ilias Tsitsimpis
    """Attaches to an extstorage block device.
48 87e9bdb7 Ilias Tsitsimpis

49 87e9bdb7 Ilias Tsitsimpis
    """
50 87e9bdb7 Ilias Tsitsimpis
    super(ExtStorageDevice, self).__init__(unique_id, children, size, params,
51 87e9bdb7 Ilias Tsitsimpis
                                           dyn_params, *args)
52 87e9bdb7 Ilias Tsitsimpis
    (self.name, self.uuid) = args
53 87e9bdb7 Ilias Tsitsimpis
54 87e9bdb7 Ilias Tsitsimpis
    if not isinstance(unique_id, (tuple, list)) or len(unique_id) != 2:
55 87e9bdb7 Ilias Tsitsimpis
      raise ValueError("Invalid configuration data %s" % str(unique_id))
56 87e9bdb7 Ilias Tsitsimpis
57 87e9bdb7 Ilias Tsitsimpis
    self.driver, self.vol_name = unique_id
58 87e9bdb7 Ilias Tsitsimpis
    self.ext_params = params
59 87e9bdb7 Ilias Tsitsimpis
60 87e9bdb7 Ilias Tsitsimpis
    self.major = self.minor = None
61 13d30fe9 Ilias Tsitsimpis
    self.uris = []
62 87e9bdb7 Ilias Tsitsimpis
    self.Attach()
63 87e9bdb7 Ilias Tsitsimpis
64 87e9bdb7 Ilias Tsitsimpis
  @classmethod
65 87e9bdb7 Ilias Tsitsimpis
  def Create(cls, unique_id, children, size, spindles, params, excl_stor,
66 87e9bdb7 Ilias Tsitsimpis
             dyn_params, *args):
67 87e9bdb7 Ilias Tsitsimpis
    """Create a new extstorage device.
68 87e9bdb7 Ilias Tsitsimpis

69 87e9bdb7 Ilias Tsitsimpis
    Provision a new volume using an extstorage provider, which will
70 87e9bdb7 Ilias Tsitsimpis
    then be mapped to a block device.
71 87e9bdb7 Ilias Tsitsimpis

72 87e9bdb7 Ilias Tsitsimpis
    """
73 87e9bdb7 Ilias Tsitsimpis
    (name, uuid) = args
74 87e9bdb7 Ilias Tsitsimpis
75 87e9bdb7 Ilias Tsitsimpis
    if not isinstance(unique_id, (tuple, list)) or len(unique_id) != 2:
76 87e9bdb7 Ilias Tsitsimpis
      raise errors.ProgrammerError("Invalid configuration data %s" %
77 87e9bdb7 Ilias Tsitsimpis
                                   str(unique_id))
78 87e9bdb7 Ilias Tsitsimpis
    if excl_stor:
79 87e9bdb7 Ilias Tsitsimpis
      raise errors.ProgrammerError("extstorage device requested with"
80 87e9bdb7 Ilias Tsitsimpis
                                   " exclusive_storage")
81 87e9bdb7 Ilias Tsitsimpis
82 87e9bdb7 Ilias Tsitsimpis
    # Call the External Storage's create script,
83 87e9bdb7 Ilias Tsitsimpis
    # to provision a new Volume inside the External Storage
84 87e9bdb7 Ilias Tsitsimpis
    _ExtStorageAction(constants.ES_ACTION_CREATE, unique_id,
85 87e9bdb7 Ilias Tsitsimpis
                      params, size=str(size), name=name, uuid=uuid)
86 87e9bdb7 Ilias Tsitsimpis
87 87e9bdb7 Ilias Tsitsimpis
    return ExtStorageDevice(unique_id, children, size, params, dyn_params,
88 87e9bdb7 Ilias Tsitsimpis
                            *args)
89 87e9bdb7 Ilias Tsitsimpis
90 87e9bdb7 Ilias Tsitsimpis
  def Remove(self):
91 87e9bdb7 Ilias Tsitsimpis
    """Remove the extstorage device.
92 87e9bdb7 Ilias Tsitsimpis

93 87e9bdb7 Ilias Tsitsimpis
    """
94 87e9bdb7 Ilias Tsitsimpis
    if not self.minor and not self.Attach():
95 87e9bdb7 Ilias Tsitsimpis
      # The extstorage device doesn't exist.
96 87e9bdb7 Ilias Tsitsimpis
      return
97 87e9bdb7 Ilias Tsitsimpis
98 87e9bdb7 Ilias Tsitsimpis
    # First shutdown the device (remove mappings).
99 87e9bdb7 Ilias Tsitsimpis
    self.Shutdown()
100 87e9bdb7 Ilias Tsitsimpis
101 87e9bdb7 Ilias Tsitsimpis
    # Call the External Storage's remove script,
102 87e9bdb7 Ilias Tsitsimpis
    # to remove the Volume from the External Storage
103 87e9bdb7 Ilias Tsitsimpis
    _ExtStorageAction(constants.ES_ACTION_REMOVE, self.unique_id,
104 87e9bdb7 Ilias Tsitsimpis
                      self.ext_params, name=self.name, uuid=self.uuid)
105 87e9bdb7 Ilias Tsitsimpis
106 87e9bdb7 Ilias Tsitsimpis
  def Rename(self, new_id):
107 87e9bdb7 Ilias Tsitsimpis
    """Rename this device.
108 87e9bdb7 Ilias Tsitsimpis

109 87e9bdb7 Ilias Tsitsimpis
    """
110 87e9bdb7 Ilias Tsitsimpis
    pass
111 87e9bdb7 Ilias Tsitsimpis
112 87e9bdb7 Ilias Tsitsimpis
  def Attach(self):
113 87e9bdb7 Ilias Tsitsimpis
    """Attach to an existing extstorage device.
114 87e9bdb7 Ilias Tsitsimpis

115 87e9bdb7 Ilias Tsitsimpis
    This method maps the extstorage volume that matches our name with
116 87e9bdb7 Ilias Tsitsimpis
    a corresponding block device and then attaches to this device.
117 87e9bdb7 Ilias Tsitsimpis

118 87e9bdb7 Ilias Tsitsimpis
    """
119 87e9bdb7 Ilias Tsitsimpis
    self.attached = False
120 87e9bdb7 Ilias Tsitsimpis
121 87e9bdb7 Ilias Tsitsimpis
    # Call the External Storage's attach script,
122 87e9bdb7 Ilias Tsitsimpis
    # to attach an existing Volume to a block device under /dev
123 13d30fe9 Ilias Tsitsimpis
    result = _ExtStorageAction(constants.ES_ACTION_ATTACH,
124 13d30fe9 Ilias Tsitsimpis
                               self.unique_id, self.ext_params,
125 13d30fe9 Ilias Tsitsimpis
                               name=self.name, uuid=self.uuid)
126 13d30fe9 Ilias Tsitsimpis
127 13d30fe9 Ilias Tsitsimpis
    # Attach script returns the block device path and optionally
128 13d30fe9 Ilias Tsitsimpis
    # the URIs to be used for userspace access (one URI for
129 13d30fe9 Ilias Tsitsimpis
    # each hypervisor supported).
130 13d30fe9 Ilias Tsitsimpis
    # If the provider doesn't support userspace access, then
131 13d30fe9 Ilias Tsitsimpis
    # the 'uris' variable will be an empty list.
132 13d30fe9 Ilias Tsitsimpis
    result = result.split("\n")
133 13d30fe9 Ilias Tsitsimpis
    self.dev_path = result[0]
134 13d30fe9 Ilias Tsitsimpis
    self.uris = result[1:]
135 13d30fe9 Ilias Tsitsimpis
136 13d30fe9 Ilias Tsitsimpis
    # Verify that dev_path exists and is a block device
137 87e9bdb7 Ilias Tsitsimpis
    try:
138 87e9bdb7 Ilias Tsitsimpis
      st = os.stat(self.dev_path)
139 87e9bdb7 Ilias Tsitsimpis
    except OSError, err:
140 87e9bdb7 Ilias Tsitsimpis
      logging.error("Error stat()'ing %s: %s", self.dev_path, str(err))
141 87e9bdb7 Ilias Tsitsimpis
      return False
142 87e9bdb7 Ilias Tsitsimpis
143 87e9bdb7 Ilias Tsitsimpis
    if not stat.S_ISBLK(st.st_mode):
144 87e9bdb7 Ilias Tsitsimpis
      logging.error("%s is not a block device", self.dev_path)
145 87e9bdb7 Ilias Tsitsimpis
      return False
146 87e9bdb7 Ilias Tsitsimpis
147 87e9bdb7 Ilias Tsitsimpis
    self.major = os.major(st.st_rdev)
148 87e9bdb7 Ilias Tsitsimpis
    self.minor = os.minor(st.st_rdev)
149 87e9bdb7 Ilias Tsitsimpis
    self.attached = True
150 87e9bdb7 Ilias Tsitsimpis
151 87e9bdb7 Ilias Tsitsimpis
    return True
152 87e9bdb7 Ilias Tsitsimpis
153 87e9bdb7 Ilias Tsitsimpis
  def Assemble(self):
154 87e9bdb7 Ilias Tsitsimpis
    """Assemble the device.
155 87e9bdb7 Ilias Tsitsimpis

156 87e9bdb7 Ilias Tsitsimpis
    """
157 87e9bdb7 Ilias Tsitsimpis
    pass
158 87e9bdb7 Ilias Tsitsimpis
159 87e9bdb7 Ilias Tsitsimpis
  def Shutdown(self):
160 87e9bdb7 Ilias Tsitsimpis
    """Shutdown the device.
161 87e9bdb7 Ilias Tsitsimpis

162 87e9bdb7 Ilias Tsitsimpis
    """
163 87e9bdb7 Ilias Tsitsimpis
    if not self.minor and not self.Attach():
164 87e9bdb7 Ilias Tsitsimpis
      # The extstorage device doesn't exist.
165 87e9bdb7 Ilias Tsitsimpis
      return
166 87e9bdb7 Ilias Tsitsimpis
167 87e9bdb7 Ilias Tsitsimpis
    # Call the External Storage's detach script,
168 87e9bdb7 Ilias Tsitsimpis
    # to detach an existing Volume from it's block device under /dev
169 87e9bdb7 Ilias Tsitsimpis
    _ExtStorageAction(constants.ES_ACTION_DETACH, self.unique_id,
170 87e9bdb7 Ilias Tsitsimpis
                      self.ext_params, name=self.name, uuid=self.uuid)
171 87e9bdb7 Ilias Tsitsimpis
172 87e9bdb7 Ilias Tsitsimpis
    self.minor = None
173 87e9bdb7 Ilias Tsitsimpis
    self.dev_path = None
174 87e9bdb7 Ilias Tsitsimpis
175 87e9bdb7 Ilias Tsitsimpis
  def Open(self, force=False):
176 87e9bdb7 Ilias Tsitsimpis
    """Make the device ready for I/O.
177 87e9bdb7 Ilias Tsitsimpis

178 87e9bdb7 Ilias Tsitsimpis
    """
179 87e9bdb7 Ilias Tsitsimpis
    pass
180 87e9bdb7 Ilias Tsitsimpis
181 87e9bdb7 Ilias Tsitsimpis
  def Close(self):
182 87e9bdb7 Ilias Tsitsimpis
    """Notifies that the device will no longer be used for I/O.
183 87e9bdb7 Ilias Tsitsimpis

184 87e9bdb7 Ilias Tsitsimpis
    """
185 87e9bdb7 Ilias Tsitsimpis
    pass
186 87e9bdb7 Ilias Tsitsimpis
187 87e9bdb7 Ilias Tsitsimpis
  def Grow(self, amount, dryrun, backingstore, excl_stor):
188 87e9bdb7 Ilias Tsitsimpis
    """Grow the Volume.
189 87e9bdb7 Ilias Tsitsimpis

190 87e9bdb7 Ilias Tsitsimpis
    @type amount: integer
191 87e9bdb7 Ilias Tsitsimpis
    @param amount: the amount (in mebibytes) to grow with
192 87e9bdb7 Ilias Tsitsimpis
    @type dryrun: boolean
193 87e9bdb7 Ilias Tsitsimpis
    @param dryrun: whether to execute the operation in simulation mode
194 87e9bdb7 Ilias Tsitsimpis
        only, without actually increasing the size
195 87e9bdb7 Ilias Tsitsimpis

196 87e9bdb7 Ilias Tsitsimpis
    """
197 87e9bdb7 Ilias Tsitsimpis
    if not backingstore:
198 87e9bdb7 Ilias Tsitsimpis
      return
199 87e9bdb7 Ilias Tsitsimpis
    if not self.Attach():
200 87e9bdb7 Ilias Tsitsimpis
      base.ThrowError("Can't attach to extstorage device during Grow()")
201 87e9bdb7 Ilias Tsitsimpis
202 87e9bdb7 Ilias Tsitsimpis
    if dryrun:
203 87e9bdb7 Ilias Tsitsimpis
      # we do not support dry runs of resize operations for now.
204 87e9bdb7 Ilias Tsitsimpis
      return
205 87e9bdb7 Ilias Tsitsimpis
206 87e9bdb7 Ilias Tsitsimpis
    new_size = self.size + amount
207 87e9bdb7 Ilias Tsitsimpis
208 87e9bdb7 Ilias Tsitsimpis
    # Call the External Storage's grow script,
209 87e9bdb7 Ilias Tsitsimpis
    # to grow an existing Volume inside the External Storage
210 87e9bdb7 Ilias Tsitsimpis
    _ExtStorageAction(constants.ES_ACTION_GROW, self.unique_id,
211 87e9bdb7 Ilias Tsitsimpis
                      self.ext_params, size=str(self.size), grow=str(new_size),
212 87e9bdb7 Ilias Tsitsimpis
                      name=self.name, uuid=self.uuid)
213 87e9bdb7 Ilias Tsitsimpis
214 87e9bdb7 Ilias Tsitsimpis
  def SetInfo(self, text):
215 87e9bdb7 Ilias Tsitsimpis
    """Update metadata with info text.
216 87e9bdb7 Ilias Tsitsimpis

217 87e9bdb7 Ilias Tsitsimpis
    """
218 87e9bdb7 Ilias Tsitsimpis
    # Replace invalid characters
219 87e9bdb7 Ilias Tsitsimpis
    text = re.sub("^[^A-Za-z0-9_+.]", "_", text)
220 87e9bdb7 Ilias Tsitsimpis
    text = re.sub("[^-A-Za-z0-9_+.]", "_", text)
221 87e9bdb7 Ilias Tsitsimpis
222 87e9bdb7 Ilias Tsitsimpis
    # Only up to 128 characters are allowed
223 87e9bdb7 Ilias Tsitsimpis
    text = text[:128]
224 87e9bdb7 Ilias Tsitsimpis
225 87e9bdb7 Ilias Tsitsimpis
    # Call the External Storage's setinfo script,
226 87e9bdb7 Ilias Tsitsimpis
    # to set metadata for an existing Volume inside the External Storage
227 87e9bdb7 Ilias Tsitsimpis
    _ExtStorageAction(constants.ES_ACTION_SETINFO, self.unique_id,
228 87e9bdb7 Ilias Tsitsimpis
                      self.ext_params, metadata=text,
229 87e9bdb7 Ilias Tsitsimpis
                      name=self.name, uuid=self.uuid)
230 87e9bdb7 Ilias Tsitsimpis
231 13d30fe9 Ilias Tsitsimpis
  def GetUserspaceAccessUri(self, hypervisor):
232 13d30fe9 Ilias Tsitsimpis
    """Generate KVM userspace URIs to be used as `-drive file` settings.
233 13d30fe9 Ilias Tsitsimpis

234 13d30fe9 Ilias Tsitsimpis
    @see: L{base.BlockDev.GetUserspaceAccessUri}
235 13d30fe9 Ilias Tsitsimpis

236 13d30fe9 Ilias Tsitsimpis
    """
237 13d30fe9 Ilias Tsitsimpis
    if not self.Attach():
238 13d30fe9 Ilias Tsitsimpis
      base.ThrowError("Can't attach to ExtStorage device")
239 13d30fe9 Ilias Tsitsimpis
240 13d30fe9 Ilias Tsitsimpis
    # If the provider supports userspace access, the attach script has
241 13d30fe9 Ilias Tsitsimpis
    # returned a list of URIs prefixed with the corresponding hypervisor.
242 13d30fe9 Ilias Tsitsimpis
    prefix = hypervisor.lower() + ":"
243 13d30fe9 Ilias Tsitsimpis
    for uri in self.uris:
244 13d30fe9 Ilias Tsitsimpis
      if uri[:len(prefix)].lower() == prefix:
245 13d30fe9 Ilias Tsitsimpis
        return uri[len(prefix):]
246 13d30fe9 Ilias Tsitsimpis
247 13d30fe9 Ilias Tsitsimpis
    base.ThrowError("Userspace access is not supported by the '%s'"
248 13d30fe9 Ilias Tsitsimpis
                    " ExtStorage provider for the '%s' hypervisor"
249 13d30fe9 Ilias Tsitsimpis
                    % (self.driver, hypervisor))
250 13d30fe9 Ilias Tsitsimpis
251 87e9bdb7 Ilias Tsitsimpis
252 87e9bdb7 Ilias Tsitsimpis
def _ExtStorageAction(action, unique_id, ext_params,
253 87e9bdb7 Ilias Tsitsimpis
                      size=None, grow=None, metadata=None,
254 87e9bdb7 Ilias Tsitsimpis
                      name=None, uuid=None):
255 87e9bdb7 Ilias Tsitsimpis
  """Take an External Storage action.
256 87e9bdb7 Ilias Tsitsimpis

257 87e9bdb7 Ilias Tsitsimpis
  Take an External Storage action concerning or affecting
258 87e9bdb7 Ilias Tsitsimpis
  a specific Volume inside the External Storage.
259 87e9bdb7 Ilias Tsitsimpis

260 87e9bdb7 Ilias Tsitsimpis
  @type action: string
261 87e9bdb7 Ilias Tsitsimpis
  @param action: which action to perform. One of:
262 87e9bdb7 Ilias Tsitsimpis
                 create / remove / grow / attach / detach
263 87e9bdb7 Ilias Tsitsimpis
  @type unique_id: tuple (driver, vol_name)
264 87e9bdb7 Ilias Tsitsimpis
  @param unique_id: a tuple containing the type of ExtStorage (driver)
265 87e9bdb7 Ilias Tsitsimpis
                    and the Volume name
266 87e9bdb7 Ilias Tsitsimpis
  @type ext_params: dict
267 87e9bdb7 Ilias Tsitsimpis
  @param ext_params: ExtStorage parameters
268 87e9bdb7 Ilias Tsitsimpis
  @type size: integer
269 87e9bdb7 Ilias Tsitsimpis
  @param size: the size of the Volume in mebibytes
270 87e9bdb7 Ilias Tsitsimpis
  @type grow: integer
271 87e9bdb7 Ilias Tsitsimpis
  @param grow: the new size in mebibytes (after grow)
272 87e9bdb7 Ilias Tsitsimpis
  @type metadata: string
273 87e9bdb7 Ilias Tsitsimpis
  @param metadata: metadata info of the Volume, for use by the provider
274 87e9bdb7 Ilias Tsitsimpis
  @type name: string
275 87e9bdb7 Ilias Tsitsimpis
  @param name: name of the Volume (objects.Disk.name)
276 87e9bdb7 Ilias Tsitsimpis
  @type uuid: string
277 87e9bdb7 Ilias Tsitsimpis
  @param uuid: uuid of the Volume (objects.Disk.uuid)
278 87e9bdb7 Ilias Tsitsimpis
  @rtype: None or a block device path (during attach)
279 87e9bdb7 Ilias Tsitsimpis

280 87e9bdb7 Ilias Tsitsimpis
  """
281 87e9bdb7 Ilias Tsitsimpis
  driver, vol_name = unique_id
282 87e9bdb7 Ilias Tsitsimpis
283 87e9bdb7 Ilias Tsitsimpis
  # Create an External Storage instance of type `driver'
284 87e9bdb7 Ilias Tsitsimpis
  status, inst_es = ExtStorageFromDisk(driver)
285 87e9bdb7 Ilias Tsitsimpis
  if not status:
286 87e9bdb7 Ilias Tsitsimpis
    base.ThrowError("%s" % inst_es)
287 87e9bdb7 Ilias Tsitsimpis
288 87e9bdb7 Ilias Tsitsimpis
  # Create the basic environment for the driver's scripts
289 87e9bdb7 Ilias Tsitsimpis
  create_env = _ExtStorageEnvironment(unique_id, ext_params, size,
290 87e9bdb7 Ilias Tsitsimpis
                                      grow, metadata, name, uuid)
291 87e9bdb7 Ilias Tsitsimpis
292 87e9bdb7 Ilias Tsitsimpis
  # Do not use log file for action `attach' as we need
293 87e9bdb7 Ilias Tsitsimpis
  # to get the output from RunResult
294 87e9bdb7 Ilias Tsitsimpis
  # TODO: find a way to have a log file for attach too
295 87e9bdb7 Ilias Tsitsimpis
  logfile = None
296 87e9bdb7 Ilias Tsitsimpis
  if action is not constants.ES_ACTION_ATTACH:
297 87e9bdb7 Ilias Tsitsimpis
    logfile = _VolumeLogName(action, driver, vol_name)
298 87e9bdb7 Ilias Tsitsimpis
299 87e9bdb7 Ilias Tsitsimpis
  # Make sure the given action results in a valid script
300 87e9bdb7 Ilias Tsitsimpis
  if action not in constants.ES_SCRIPTS:
301 87e9bdb7 Ilias Tsitsimpis
    base.ThrowError("Action '%s' doesn't result in a valid ExtStorage script" %
302 87e9bdb7 Ilias Tsitsimpis
                    action)
303 87e9bdb7 Ilias Tsitsimpis
304 87e9bdb7 Ilias Tsitsimpis
  # Find out which external script to run according the given action
305 87e9bdb7 Ilias Tsitsimpis
  script_name = action + "_script"
306 87e9bdb7 Ilias Tsitsimpis
  script = getattr(inst_es, script_name)
307 87e9bdb7 Ilias Tsitsimpis
308 87e9bdb7 Ilias Tsitsimpis
  # Run the external script
309 87e9bdb7 Ilias Tsitsimpis
  result = utils.RunCmd([script], env=create_env,
310 87e9bdb7 Ilias Tsitsimpis
                        cwd=inst_es.path, output=logfile,)
311 87e9bdb7 Ilias Tsitsimpis
  if result.failed:
312 87e9bdb7 Ilias Tsitsimpis
    logging.error("External storage's %s command '%s' returned"
313 87e9bdb7 Ilias Tsitsimpis
                  " error: %s, logfile: %s, output: %s",
314 87e9bdb7 Ilias Tsitsimpis
                  action, result.cmd, result.fail_reason,
315 87e9bdb7 Ilias Tsitsimpis
                  logfile, result.output)
316 87e9bdb7 Ilias Tsitsimpis
317 87e9bdb7 Ilias Tsitsimpis
    # If logfile is 'None' (during attach), it breaks TailFile
318 87e9bdb7 Ilias Tsitsimpis
    # TODO: have a log file for attach too
319 87e9bdb7 Ilias Tsitsimpis
    if action is not constants.ES_ACTION_ATTACH:
320 87e9bdb7 Ilias Tsitsimpis
      lines = [utils.SafeEncode(val)
321 87e9bdb7 Ilias Tsitsimpis
               for val in utils.TailFile(logfile, lines=20)]
322 87e9bdb7 Ilias Tsitsimpis
    else:
323 87e9bdb7 Ilias Tsitsimpis
      lines = result.output[-20:]
324 87e9bdb7 Ilias Tsitsimpis
325 87e9bdb7 Ilias Tsitsimpis
    base.ThrowError("External storage's %s script failed (%s), last"
326 87e9bdb7 Ilias Tsitsimpis
                    " lines of output:\n%s",
327 87e9bdb7 Ilias Tsitsimpis
                    action, result.fail_reason, "\n".join(lines))
328 87e9bdb7 Ilias Tsitsimpis
329 87e9bdb7 Ilias Tsitsimpis
  if action == constants.ES_ACTION_ATTACH:
330 87e9bdb7 Ilias Tsitsimpis
    return result.stdout
331 87e9bdb7 Ilias Tsitsimpis
332 87e9bdb7 Ilias Tsitsimpis
333 87e9bdb7 Ilias Tsitsimpis
def ExtStorageFromDisk(name, base_dir=None):
334 87e9bdb7 Ilias Tsitsimpis
  """Create an ExtStorage instance from disk.
335 87e9bdb7 Ilias Tsitsimpis

336 87e9bdb7 Ilias Tsitsimpis
  This function will return an ExtStorage instance
337 87e9bdb7 Ilias Tsitsimpis
  if the given name is a valid ExtStorage name.
338 87e9bdb7 Ilias Tsitsimpis

339 87e9bdb7 Ilias Tsitsimpis
  @type base_dir: string
340 87e9bdb7 Ilias Tsitsimpis
  @keyword base_dir: Base directory containing ExtStorage installations.
341 87e9bdb7 Ilias Tsitsimpis
                     Defaults to a search in all the ES_SEARCH_PATH dirs.
342 87e9bdb7 Ilias Tsitsimpis
  @rtype: tuple
343 87e9bdb7 Ilias Tsitsimpis
  @return: True and the ExtStorage instance if we find a valid one, or
344 87e9bdb7 Ilias Tsitsimpis
      False and the diagnose message on error
345 87e9bdb7 Ilias Tsitsimpis

346 87e9bdb7 Ilias Tsitsimpis
  """
347 87e9bdb7 Ilias Tsitsimpis
  if base_dir is None:
348 87e9bdb7 Ilias Tsitsimpis
    es_base_dir = pathutils.ES_SEARCH_PATH
349 87e9bdb7 Ilias Tsitsimpis
  else:
350 87e9bdb7 Ilias Tsitsimpis
    es_base_dir = [base_dir]
351 87e9bdb7 Ilias Tsitsimpis
352 87e9bdb7 Ilias Tsitsimpis
  es_dir = utils.FindFile(name, es_base_dir, os.path.isdir)
353 87e9bdb7 Ilias Tsitsimpis
354 87e9bdb7 Ilias Tsitsimpis
  if es_dir is None:
355 87e9bdb7 Ilias Tsitsimpis
    return False, ("Directory for External Storage Provider %s not"
356 87e9bdb7 Ilias Tsitsimpis
                   " found in search path" % name)
357 87e9bdb7 Ilias Tsitsimpis
358 87e9bdb7 Ilias Tsitsimpis
  # ES Files dictionary, we will populate it with the absolute path
359 87e9bdb7 Ilias Tsitsimpis
  # names; if the value is True, then it is a required file, otherwise
360 87e9bdb7 Ilias Tsitsimpis
  # an optional one
361 87e9bdb7 Ilias Tsitsimpis
  es_files = dict.fromkeys(constants.ES_SCRIPTS, True)
362 87e9bdb7 Ilias Tsitsimpis
363 87e9bdb7 Ilias Tsitsimpis
  es_files[constants.ES_PARAMETERS_FILE] = True
364 87e9bdb7 Ilias Tsitsimpis
365 87e9bdb7 Ilias Tsitsimpis
  for (filename, _) in es_files.items():
366 87e9bdb7 Ilias Tsitsimpis
    es_files[filename] = utils.PathJoin(es_dir, filename)
367 87e9bdb7 Ilias Tsitsimpis
368 87e9bdb7 Ilias Tsitsimpis
    try:
369 87e9bdb7 Ilias Tsitsimpis
      st = os.stat(es_files[filename])
370 87e9bdb7 Ilias Tsitsimpis
    except EnvironmentError, err:
371 87e9bdb7 Ilias Tsitsimpis
      return False, ("File '%s' under path '%s' is missing (%s)" %
372 87e9bdb7 Ilias Tsitsimpis
                     (filename, es_dir, utils.ErrnoOrStr(err)))
373 87e9bdb7 Ilias Tsitsimpis
374 87e9bdb7 Ilias Tsitsimpis
    if not stat.S_ISREG(stat.S_IFMT(st.st_mode)):
375 87e9bdb7 Ilias Tsitsimpis
      return False, ("File '%s' under path '%s' is not a regular file" %
376 87e9bdb7 Ilias Tsitsimpis
                     (filename, es_dir))
377 87e9bdb7 Ilias Tsitsimpis
378 87e9bdb7 Ilias Tsitsimpis
    if filename in constants.ES_SCRIPTS:
379 87e9bdb7 Ilias Tsitsimpis
      if stat.S_IMODE(st.st_mode) & stat.S_IXUSR != stat.S_IXUSR:
380 87e9bdb7 Ilias Tsitsimpis
        return False, ("File '%s' under path '%s' is not executable" %
381 87e9bdb7 Ilias Tsitsimpis
                       (filename, es_dir))
382 87e9bdb7 Ilias Tsitsimpis
383 87e9bdb7 Ilias Tsitsimpis
  parameters = []
384 87e9bdb7 Ilias Tsitsimpis
  if constants.ES_PARAMETERS_FILE in es_files:
385 87e9bdb7 Ilias Tsitsimpis
    parameters_file = es_files[constants.ES_PARAMETERS_FILE]
386 87e9bdb7 Ilias Tsitsimpis
    try:
387 87e9bdb7 Ilias Tsitsimpis
      parameters = utils.ReadFile(parameters_file).splitlines()
388 87e9bdb7 Ilias Tsitsimpis
    except EnvironmentError, err:
389 87e9bdb7 Ilias Tsitsimpis
      return False, ("Error while reading the EXT parameters file at %s: %s" %
390 87e9bdb7 Ilias Tsitsimpis
                     (parameters_file, utils.ErrnoOrStr(err)))
391 87e9bdb7 Ilias Tsitsimpis
    parameters = [v.split(None, 1) for v in parameters]
392 87e9bdb7 Ilias Tsitsimpis
393 87e9bdb7 Ilias Tsitsimpis
  es_obj = \
394 87e9bdb7 Ilias Tsitsimpis
    objects.ExtStorage(name=name, path=es_dir,
395 87e9bdb7 Ilias Tsitsimpis
                       create_script=es_files[constants.ES_SCRIPT_CREATE],
396 87e9bdb7 Ilias Tsitsimpis
                       remove_script=es_files[constants.ES_SCRIPT_REMOVE],
397 87e9bdb7 Ilias Tsitsimpis
                       grow_script=es_files[constants.ES_SCRIPT_GROW],
398 87e9bdb7 Ilias Tsitsimpis
                       attach_script=es_files[constants.ES_SCRIPT_ATTACH],
399 87e9bdb7 Ilias Tsitsimpis
                       detach_script=es_files[constants.ES_SCRIPT_DETACH],
400 87e9bdb7 Ilias Tsitsimpis
                       setinfo_script=es_files[constants.ES_SCRIPT_SETINFO],
401 87e9bdb7 Ilias Tsitsimpis
                       verify_script=es_files[constants.ES_SCRIPT_VERIFY],
402 87e9bdb7 Ilias Tsitsimpis
                       supported_parameters=parameters)
403 87e9bdb7 Ilias Tsitsimpis
  return True, es_obj
404 87e9bdb7 Ilias Tsitsimpis
405 87e9bdb7 Ilias Tsitsimpis
406 87e9bdb7 Ilias Tsitsimpis
def _ExtStorageEnvironment(unique_id, ext_params,
407 87e9bdb7 Ilias Tsitsimpis
                           size=None, grow=None, metadata=None,
408 87e9bdb7 Ilias Tsitsimpis
                           name=None, uuid=None):
409 87e9bdb7 Ilias Tsitsimpis
  """Calculate the environment for an External Storage script.
410 87e9bdb7 Ilias Tsitsimpis

411 87e9bdb7 Ilias Tsitsimpis
  @type unique_id: tuple (driver, vol_name)
412 87e9bdb7 Ilias Tsitsimpis
  @param unique_id: ExtStorage pool and name of the Volume
413 87e9bdb7 Ilias Tsitsimpis
  @type ext_params: dict
414 87e9bdb7 Ilias Tsitsimpis
  @param ext_params: the EXT parameters
415 87e9bdb7 Ilias Tsitsimpis
  @type size: string
416 87e9bdb7 Ilias Tsitsimpis
  @param size: size of the Volume (in mebibytes)
417 87e9bdb7 Ilias Tsitsimpis
  @type grow: string
418 87e9bdb7 Ilias Tsitsimpis
  @param grow: new size of Volume after grow (in mebibytes)
419 87e9bdb7 Ilias Tsitsimpis
  @type metadata: string
420 87e9bdb7 Ilias Tsitsimpis
  @param metadata: metadata info of the Volume
421 87e9bdb7 Ilias Tsitsimpis
  @type name: string
422 87e9bdb7 Ilias Tsitsimpis
  @param name: name of the Volume (objects.Disk.name)
423 87e9bdb7 Ilias Tsitsimpis
  @type uuid: string
424 87e9bdb7 Ilias Tsitsimpis
  @param uuid: uuid of the Volume (objects.Disk.uuid)
425 87e9bdb7 Ilias Tsitsimpis
  @rtype: dict
426 87e9bdb7 Ilias Tsitsimpis
  @return: dict of environment variables
427 87e9bdb7 Ilias Tsitsimpis

428 87e9bdb7 Ilias Tsitsimpis
  """
429 87e9bdb7 Ilias Tsitsimpis
  vol_name = unique_id[1]
430 87e9bdb7 Ilias Tsitsimpis
431 87e9bdb7 Ilias Tsitsimpis
  result = {}
432 87e9bdb7 Ilias Tsitsimpis
  result["VOL_NAME"] = vol_name
433 87e9bdb7 Ilias Tsitsimpis
434 87e9bdb7 Ilias Tsitsimpis
  # EXT params
435 87e9bdb7 Ilias Tsitsimpis
  for pname, pvalue in ext_params.items():
436 87e9bdb7 Ilias Tsitsimpis
    result["EXTP_%s" % pname.upper()] = str(pvalue)
437 87e9bdb7 Ilias Tsitsimpis
438 87e9bdb7 Ilias Tsitsimpis
  if size is not None:
439 87e9bdb7 Ilias Tsitsimpis
    result["VOL_SIZE"] = size
440 87e9bdb7 Ilias Tsitsimpis
441 87e9bdb7 Ilias Tsitsimpis
  if grow is not None:
442 87e9bdb7 Ilias Tsitsimpis
    result["VOL_NEW_SIZE"] = grow
443 87e9bdb7 Ilias Tsitsimpis
444 87e9bdb7 Ilias Tsitsimpis
  if metadata is not None:
445 87e9bdb7 Ilias Tsitsimpis
    result["VOL_METADATA"] = metadata
446 87e9bdb7 Ilias Tsitsimpis
447 87e9bdb7 Ilias Tsitsimpis
  if name is not None:
448 87e9bdb7 Ilias Tsitsimpis
    result["VOL_CNAME"] = name
449 87e9bdb7 Ilias Tsitsimpis
450 87e9bdb7 Ilias Tsitsimpis
  if uuid is not None:
451 87e9bdb7 Ilias Tsitsimpis
    result["VOL_UUID"] = uuid
452 87e9bdb7 Ilias Tsitsimpis
453 87e9bdb7 Ilias Tsitsimpis
  return result
454 87e9bdb7 Ilias Tsitsimpis
455 87e9bdb7 Ilias Tsitsimpis
456 87e9bdb7 Ilias Tsitsimpis
def _VolumeLogName(kind, es_name, volume):
457 87e9bdb7 Ilias Tsitsimpis
  """Compute the ExtStorage log filename for a given Volume and operation.
458 87e9bdb7 Ilias Tsitsimpis

459 87e9bdb7 Ilias Tsitsimpis
  @type kind: string
460 87e9bdb7 Ilias Tsitsimpis
  @param kind: the operation type (e.g. create, remove etc.)
461 87e9bdb7 Ilias Tsitsimpis
  @type es_name: string
462 87e9bdb7 Ilias Tsitsimpis
  @param es_name: the ExtStorage name
463 87e9bdb7 Ilias Tsitsimpis
  @type volume: string
464 87e9bdb7 Ilias Tsitsimpis
  @param volume: the name of the Volume inside the External Storage
465 87e9bdb7 Ilias Tsitsimpis

466 87e9bdb7 Ilias Tsitsimpis
  """
467 87e9bdb7 Ilias Tsitsimpis
  # Check if the extstorage log dir is a valid dir
468 87e9bdb7 Ilias Tsitsimpis
  if not os.path.isdir(pathutils.LOG_ES_DIR):
469 87e9bdb7 Ilias Tsitsimpis
    base.ThrowError("Cannot find log directory: %s", pathutils.LOG_ES_DIR)
470 87e9bdb7 Ilias Tsitsimpis
471 87e9bdb7 Ilias Tsitsimpis
  # TODO: Use tempfile.mkstemp to create unique filename
472 87e9bdb7 Ilias Tsitsimpis
  basename = ("%s-%s-%s-%s.log" %
473 87e9bdb7 Ilias Tsitsimpis
              (kind, es_name, volume, utils.TimestampForFilename()))
474 87e9bdb7 Ilias Tsitsimpis
  return utils.PathJoin(pathutils.LOG_ES_DIR, basename)