Statistics
| Branch: | Tag: | Revision:

root / daemons / ganeti-noded @ ff5fac04

History | View | Annotate | Download (17 kB)

1 a8083063 Iustin Pop
#!/usr/bin/python
2 a8083063 Iustin Pop
#
3 a8083063 Iustin Pop
4 a8083063 Iustin Pop
# Copyright (C) 2006, 2007 Google Inc.
5 a8083063 Iustin Pop
#
6 a8083063 Iustin Pop
# This program is free software; you can redistribute it and/or modify
7 a8083063 Iustin Pop
# it under the terms of the GNU General Public License as published by
8 a8083063 Iustin Pop
# the Free Software Foundation; either version 2 of the License, or
9 a8083063 Iustin Pop
# (at your option) any later version.
10 a8083063 Iustin Pop
#
11 a8083063 Iustin Pop
# This program is distributed in the hope that it will be useful, but
12 a8083063 Iustin Pop
# WITHOUT ANY WARRANTY; without even the implied warranty of
13 a8083063 Iustin Pop
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 a8083063 Iustin Pop
# General Public License for more details.
15 a8083063 Iustin Pop
#
16 a8083063 Iustin Pop
# You should have received a copy of the GNU General Public License
17 a8083063 Iustin Pop
# along with this program; if not, write to the Free Software
18 a8083063 Iustin Pop
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 a8083063 Iustin Pop
# 02110-1301, USA.
20 a8083063 Iustin Pop
21 a8083063 Iustin Pop
22 a8083063 Iustin Pop
"""Ganeti node daemon"""
23 a8083063 Iustin Pop
24 3ecf6786 Iustin Pop
# functions in this module need to have a given name structure, so:
25 3ecf6786 Iustin Pop
# pylint: disable-msg=C0103
26 3ecf6786 Iustin Pop
27 a8083063 Iustin Pop
import os
28 a8083063 Iustin Pop
import sys
29 a8083063 Iustin Pop
import traceback
30 81010134 Iustin Pop
import BaseHTTPServer
31 81010134 Iustin Pop
import simplejson
32 0214b0c0 Iustin Pop
import errno
33 c89189b1 Iustin Pop
import logging
34 a8083063 Iustin Pop
35 a8083063 Iustin Pop
from optparse import OptionParser
36 a8083063 Iustin Pop
37 a8083063 Iustin Pop
38 a8083063 Iustin Pop
from ganeti import backend
39 a8083063 Iustin Pop
from ganeti import logger
40 a8083063 Iustin Pop
from ganeti import constants
41 a8083063 Iustin Pop
from ganeti import objects
42 a8083063 Iustin Pop
from ganeti import errors
43 a8083063 Iustin Pop
from ganeti import ssconf
44 16abfbc2 Alexander Schreiber
from ganeti import utils
45 a8083063 Iustin Pop
46 c89189b1 Iustin Pop
_EXIT_GANETI_NODED = False
47 c89189b1 Iustin Pop
48 a8083063 Iustin Pop
49 81010134 Iustin Pop
class ServerObject(BaseHTTPServer.BaseHTTPRequestHandler):
50 3ecf6786 Iustin Pop
  """The server implementation.
51 3ecf6786 Iustin Pop
52 3ecf6786 Iustin Pop
  This class holds all methods exposed over the RPC interface.
53 3ecf6786 Iustin Pop
54 3ecf6786 Iustin Pop
  """
55 81010134 Iustin Pop
  def do_PUT(self):
56 81010134 Iustin Pop
    """Handle a post request.
57 a8083063 Iustin Pop
58 098c0958 Michael Hanselmann
    """
59 81010134 Iustin Pop
    path = self.path
60 81010134 Iustin Pop
    if path.startswith("/"):
61 81010134 Iustin Pop
      path = path[1:]
62 c89189b1 Iustin Pop
    logging.debug("ServerObject: received call '%s'", path)
63 81010134 Iustin Pop
    mname = "perspective_%s" % path
64 81010134 Iustin Pop
    if not hasattr(self, mname):
65 81010134 Iustin Pop
      self.send_error(404)
66 81010134 Iustin Pop
      return False
67 81010134 Iustin Pop
68 81010134 Iustin Pop
    method = getattr(self, mname)
69 a8083063 Iustin Pop
    try:
70 81010134 Iustin Pop
      body_length = int(self.headers.get('Content-Length', '0'))
71 81010134 Iustin Pop
    except ValueError:
72 81010134 Iustin Pop
      self.send_error(400, 'No Content-Length header or invalid format')
73 81010134 Iustin Pop
      return False
74 a8083063 Iustin Pop
75 81010134 Iustin Pop
    try:
76 81010134 Iustin Pop
      body = self.rfile.read(body_length)
77 81010134 Iustin Pop
    except socket.error, err:
78 81010134 Iustin Pop
      logger.Error("Socket error while reading: %s" % str(err))
79 81010134 Iustin Pop
      return
80 81010134 Iustin Pop
    try:
81 81010134 Iustin Pop
      params = simplejson.loads(body)
82 c89189b1 Iustin Pop
      logging.debug("ServerObject: method parameters: %s", params)
83 81010134 Iustin Pop
      result = method(params)
84 81010134 Iustin Pop
      payload = simplejson.dumps(result)
85 9ae49f27 Guido Trotter
    except errors.QuitGanetiException, err:
86 9ae49f27 Guido Trotter
      global _EXIT_GANETI_NODED
87 9ae49f27 Guido Trotter
      _EXIT_GANETI_NODED = True
88 c3d7f69b Guido Trotter
      if isinstance(err.args, tuple) and len(err.args) == 2:
89 c3d7f69b Guido Trotter
        if err.args[0]:
90 9ae49f27 Guido Trotter
          self.send_error(500, "Error: %s" % str(err[1]))
91 9ae49f27 Guido Trotter
        else:
92 c3d7f69b Guido Trotter
          payload = simplejson.dumps(err.args[1])
93 9ae49f27 Guido Trotter
      else:
94 c3d7f69b Guido Trotter
        self.log_message('QuitGanetiException Usage Error')
95 9ae49f27 Guido Trotter
        self.send_error(500, "Error: %s" % str(err))
96 81010134 Iustin Pop
    except Exception, err:
97 81010134 Iustin Pop
      self.send_error(500, "Error: %s" % str(err))
98 81010134 Iustin Pop
      return False
99 81010134 Iustin Pop
    self.send_response(200)
100 81010134 Iustin Pop
    self.send_header('Content-Length', str(len(payload)))
101 81010134 Iustin Pop
    self.end_headers()
102 81010134 Iustin Pop
    self.wfile.write(payload)
103 81010134 Iustin Pop
    return True
104 81010134 Iustin Pop
105 81010134 Iustin Pop
  def log_message(self, format, *args):
106 81010134 Iustin Pop
    """Log a request to the log.
107 81010134 Iustin Pop
108 81010134 Iustin Pop
    This is the same as the parent, we just log somewhere else.
109 81010134 Iustin Pop
110 81010134 Iustin Pop
    """
111 6e12fa3c Iustin Pop
    msg = ("%s - - [%s] %s" %
112 81010134 Iustin Pop
           (self.address_string(),
113 81010134 Iustin Pop
            self.log_date_time_string(),
114 81010134 Iustin Pop
            format % args))
115 c89189b1 Iustin Pop
    logging.debug(msg)
116 a8083063 Iustin Pop
117 a8083063 Iustin Pop
  # the new block devices  --------------------------
118 a8083063 Iustin Pop
119 3ecf6786 Iustin Pop
  @staticmethod
120 3ecf6786 Iustin Pop
  def perspective_blockdev_create(params):
121 3ecf6786 Iustin Pop
    """Create a block device.
122 3ecf6786 Iustin Pop
123 3ecf6786 Iustin Pop
    """
124 3f78eef2 Iustin Pop
    bdev_s, size, owner, on_primary, info = params
125 319856a9 Michael Hanselmann
    bdev = objects.Disk.FromDict(bdev_s)
126 a8083063 Iustin Pop
    if bdev is None:
127 a8083063 Iustin Pop
      raise ValueError("can't unserialize data!")
128 3f78eef2 Iustin Pop
    return backend.CreateBlockDevice(bdev, size, owner, on_primary, info)
129 a8083063 Iustin Pop
130 3ecf6786 Iustin Pop
  @staticmethod
131 3ecf6786 Iustin Pop
  def perspective_blockdev_remove(params):
132 3ecf6786 Iustin Pop
    """Remove a block device.
133 3ecf6786 Iustin Pop
134 3ecf6786 Iustin Pop
    """
135 a8083063 Iustin Pop
    bdev_s = params[0]
136 319856a9 Michael Hanselmann
    bdev = objects.Disk.FromDict(bdev_s)
137 a8083063 Iustin Pop
    return backend.RemoveBlockDevice(bdev)
138 a8083063 Iustin Pop
139 3ecf6786 Iustin Pop
  @staticmethod
140 f3e513ad Iustin Pop
  def perspective_blockdev_rename(params):
141 f3e513ad Iustin Pop
    """Remove a block device.
142 f3e513ad Iustin Pop
143 f3e513ad Iustin Pop
    """
144 f3e513ad Iustin Pop
    devlist = [(objects.Disk.FromDict(ds), uid) for ds, uid in params]
145 f3e513ad Iustin Pop
    return backend.RenameBlockDevices(devlist)
146 f3e513ad Iustin Pop
147 f3e513ad Iustin Pop
  @staticmethod
148 3ecf6786 Iustin Pop
  def perspective_blockdev_assemble(params):
149 3ecf6786 Iustin Pop
    """Assemble a block device.
150 3ecf6786 Iustin Pop
151 3ecf6786 Iustin Pop
    """
152 3f78eef2 Iustin Pop
    bdev_s, owner, on_primary = params
153 319856a9 Michael Hanselmann
    bdev = objects.Disk.FromDict(bdev_s)
154 a8083063 Iustin Pop
    if bdev is None:
155 a8083063 Iustin Pop
      raise ValueError("can't unserialize data!")
156 3f78eef2 Iustin Pop
    return backend.AssembleBlockDevice(bdev, owner, on_primary)
157 a8083063 Iustin Pop
158 3ecf6786 Iustin Pop
  @staticmethod
159 3ecf6786 Iustin Pop
  def perspective_blockdev_shutdown(params):
160 3ecf6786 Iustin Pop
    """Shutdown a block device.
161 3ecf6786 Iustin Pop
162 3ecf6786 Iustin Pop
    """
163 a8083063 Iustin Pop
    bdev_s = params[0]
164 319856a9 Michael Hanselmann
    bdev = objects.Disk.FromDict(bdev_s)
165 a8083063 Iustin Pop
    if bdev is None:
166 a8083063 Iustin Pop
      raise ValueError("can't unserialize data!")
167 a8083063 Iustin Pop
    return backend.ShutdownBlockDevice(bdev)
168 a8083063 Iustin Pop
169 3ecf6786 Iustin Pop
  @staticmethod
170 153d9724 Iustin Pop
  def perspective_blockdev_addchildren(params):
171 3ecf6786 Iustin Pop
    """Add a child to a mirror device.
172 3ecf6786 Iustin Pop
173 3ecf6786 Iustin Pop
    Note: this is only valid for mirror devices. It's the caller's duty
174 3ecf6786 Iustin Pop
    to send a correct disk, otherwise we raise an error.
175 3ecf6786 Iustin Pop
176 3ecf6786 Iustin Pop
    """
177 a8083063 Iustin Pop
    bdev_s, ndev_s = params
178 319856a9 Michael Hanselmann
    bdev = objects.Disk.FromDict(bdev_s)
179 153d9724 Iustin Pop
    ndevs = [objects.Disk.FromDict(disk_s) for disk_s in ndev_s]
180 153d9724 Iustin Pop
    if bdev is None or ndevs.count(None) > 0:
181 a8083063 Iustin Pop
      raise ValueError("can't unserialize data!")
182 153d9724 Iustin Pop
    return backend.MirrorAddChildren(bdev, ndevs)
183 a8083063 Iustin Pop
184 3ecf6786 Iustin Pop
  @staticmethod
185 153d9724 Iustin Pop
  def perspective_blockdev_removechildren(params):
186 3ecf6786 Iustin Pop
    """Remove a child from a mirror device.
187 3ecf6786 Iustin Pop
188 3ecf6786 Iustin Pop
    This is only valid for mirror devices, of course. It's the callers
189 3ecf6786 Iustin Pop
    duty to send a correct disk, otherwise we raise an error.
190 3ecf6786 Iustin Pop
191 3ecf6786 Iustin Pop
    """
192 a8083063 Iustin Pop
    bdev_s, ndev_s = params
193 319856a9 Michael Hanselmann
    bdev = objects.Disk.FromDict(bdev_s)
194 153d9724 Iustin Pop
    ndevs = [objects.Disk.FromDict(disk_s) for disk_s in ndev_s]
195 153d9724 Iustin Pop
    if bdev is None or ndevs.count(None) > 0:
196 a8083063 Iustin Pop
      raise ValueError("can't unserialize data!")
197 153d9724 Iustin Pop
    return backend.MirrorRemoveChildren(bdev, ndevs)
198 a8083063 Iustin Pop
199 3ecf6786 Iustin Pop
  @staticmethod
200 3ecf6786 Iustin Pop
  def perspective_blockdev_getmirrorstatus(params):
201 3ecf6786 Iustin Pop
    """Return the mirror status for a list of disks.
202 3ecf6786 Iustin Pop
203 3ecf6786 Iustin Pop
    """
204 319856a9 Michael Hanselmann
    disks = [objects.Disk.FromDict(dsk_s)
205 a8083063 Iustin Pop
            for dsk_s in params]
206 a8083063 Iustin Pop
    return backend.GetMirrorStatus(disks)
207 a8083063 Iustin Pop
208 3ecf6786 Iustin Pop
  @staticmethod
209 3ecf6786 Iustin Pop
  def perspective_blockdev_find(params):
210 3ecf6786 Iustin Pop
    """Expose the FindBlockDevice functionality for a disk.
211 3ecf6786 Iustin Pop
212 3ecf6786 Iustin Pop
    This will try to find but not activate a disk.
213 3ecf6786 Iustin Pop
214 3ecf6786 Iustin Pop
    """
215 319856a9 Michael Hanselmann
    disk = objects.Disk.FromDict(params[0])
216 a8083063 Iustin Pop
    return backend.FindBlockDevice(disk)
217 a8083063 Iustin Pop
218 3ecf6786 Iustin Pop
  @staticmethod
219 3ecf6786 Iustin Pop
  def perspective_blockdev_snapshot(params):
220 3ecf6786 Iustin Pop
    """Create a snapshot device.
221 3ecf6786 Iustin Pop
222 3ecf6786 Iustin Pop
    Note that this is only valid for LVM disks, if we get passed
223 3ecf6786 Iustin Pop
    something else we raise an exception. The snapshot device can be
224 3ecf6786 Iustin Pop
    remove by calling the generic block device remove call.
225 3ecf6786 Iustin Pop
226 3ecf6786 Iustin Pop
    """
227 319856a9 Michael Hanselmann
    cfbd = objects.Disk.FromDict(params[0])
228 a8083063 Iustin Pop
    return backend.SnapshotBlockDevice(cfbd)
229 a8083063 Iustin Pop
230 4c8ba8b3 Iustin Pop
  @staticmethod
231 4c8ba8b3 Iustin Pop
  def perspective_blockdev_grow(params):
232 4c8ba8b3 Iustin Pop
    """Grow a stack of devices.
233 4c8ba8b3 Iustin Pop
234 4c8ba8b3 Iustin Pop
    """
235 4c8ba8b3 Iustin Pop
    cfbd = objects.Disk.FromDict(params[0])
236 4c8ba8b3 Iustin Pop
    amount = params[1]
237 4c8ba8b3 Iustin Pop
    return backend.GrowBlockDevice(cfbd, amount)
238 4c8ba8b3 Iustin Pop
239 d61cbe76 Iustin Pop
  @staticmethod
240 d61cbe76 Iustin Pop
  def perspective_blockdev_close(params):
241 d61cbe76 Iustin Pop
    """Closes the given block devices.
242 d61cbe76 Iustin Pop
243 d61cbe76 Iustin Pop
    """
244 d61cbe76 Iustin Pop
    disks = [objects.Disk.FromDict(cf) for cf in params]
245 d61cbe76 Iustin Pop
    return backend.CloseBlockDevices(disks)
246 d61cbe76 Iustin Pop
247 a8083063 Iustin Pop
  # export/import  --------------------------
248 a8083063 Iustin Pop
249 3ecf6786 Iustin Pop
  @staticmethod
250 3ecf6786 Iustin Pop
  def perspective_snapshot_export(params):
251 3ecf6786 Iustin Pop
    """Export a given snapshot.
252 3ecf6786 Iustin Pop
253 3ecf6786 Iustin Pop
    """
254 319856a9 Michael Hanselmann
    disk = objects.Disk.FromDict(params[0])
255 a8083063 Iustin Pop
    dest_node = params[1]
256 319856a9 Michael Hanselmann
    instance = objects.Instance.FromDict(params[2])
257 3ecf6786 Iustin Pop
    return backend.ExportSnapshot(disk, dest_node, instance)
258 3ecf6786 Iustin Pop
259 3ecf6786 Iustin Pop
  @staticmethod
260 3ecf6786 Iustin Pop
  def perspective_finalize_export(params):
261 3ecf6786 Iustin Pop
    """Expose the finalize export functionality.
262 a8083063 Iustin Pop
263 3ecf6786 Iustin Pop
    """
264 319856a9 Michael Hanselmann
    instance = objects.Instance.FromDict(params[0])
265 319856a9 Michael Hanselmann
    snap_disks = [objects.Disk.FromDict(str_data)
266 a8083063 Iustin Pop
                  for str_data in params[1]]
267 a8083063 Iustin Pop
    return backend.FinalizeExport(instance, snap_disks)
268 a8083063 Iustin Pop
269 3ecf6786 Iustin Pop
  @staticmethod
270 3ecf6786 Iustin Pop
  def perspective_export_info(params):
271 3ecf6786 Iustin Pop
    """Query information about an existing export on this node.
272 3ecf6786 Iustin Pop
273 3ecf6786 Iustin Pop
    The given path may not contain an export, in which case we return
274 3ecf6786 Iustin Pop
    None.
275 3ecf6786 Iustin Pop
276 3ecf6786 Iustin Pop
    """
277 3ecf6786 Iustin Pop
    path = params[0]
278 3ecf6786 Iustin Pop
    einfo = backend.ExportInfo(path)
279 a8083063 Iustin Pop
    if einfo is None:
280 a8083063 Iustin Pop
      return einfo
281 a8083063 Iustin Pop
    return einfo.Dumps()
282 a8083063 Iustin Pop
283 3ecf6786 Iustin Pop
  @staticmethod
284 3ecf6786 Iustin Pop
  def perspective_export_list(params):
285 3ecf6786 Iustin Pop
    """List the available exports on this node.
286 3ecf6786 Iustin Pop
287 3ecf6786 Iustin Pop
    Note that as opposed to export_info, which may query data about an
288 3ecf6786 Iustin Pop
    export in any path, this only queries the standard Ganeti path
289 3ecf6786 Iustin Pop
    (constants.EXPORT_DIR).
290 3ecf6786 Iustin Pop
291 3ecf6786 Iustin Pop
    """
292 a8083063 Iustin Pop
    return backend.ListExports()
293 a8083063 Iustin Pop
294 3ecf6786 Iustin Pop
  @staticmethod
295 3ecf6786 Iustin Pop
  def perspective_export_remove(params):
296 3ecf6786 Iustin Pop
    """Remove an export.
297 3ecf6786 Iustin Pop
298 3ecf6786 Iustin Pop
    """
299 a8083063 Iustin Pop
    export = params[0]
300 a8083063 Iustin Pop
    return backend.RemoveExport(export)
301 a8083063 Iustin Pop
302 a8083063 Iustin Pop
  # volume  --------------------------
303 a8083063 Iustin Pop
304 3ecf6786 Iustin Pop
  @staticmethod
305 3ecf6786 Iustin Pop
  def perspective_volume_list(params):
306 3ecf6786 Iustin Pop
    """Query the list of logical volumes in a given volume group.
307 3ecf6786 Iustin Pop
308 3ecf6786 Iustin Pop
    """
309 a8083063 Iustin Pop
    vgname = params[0]
310 a8083063 Iustin Pop
    return backend.GetVolumeList(vgname)
311 a8083063 Iustin Pop
312 3ecf6786 Iustin Pop
  @staticmethod
313 3ecf6786 Iustin Pop
  def perspective_vg_list(params):
314 3ecf6786 Iustin Pop
    """Query the list of volume groups.
315 3ecf6786 Iustin Pop
316 3ecf6786 Iustin Pop
    """
317 a8083063 Iustin Pop
    return backend.ListVolumeGroups()
318 a8083063 Iustin Pop
319 a8083063 Iustin Pop
  # bridge  --------------------------
320 a8083063 Iustin Pop
321 3ecf6786 Iustin Pop
  @staticmethod
322 3ecf6786 Iustin Pop
  def perspective_bridges_exist(params):
323 3ecf6786 Iustin Pop
    """Check if all bridges given exist on this node.
324 3ecf6786 Iustin Pop
325 3ecf6786 Iustin Pop
    """
326 a8083063 Iustin Pop
    bridges_list = params[0]
327 a8083063 Iustin Pop
    return backend.BridgesExist(bridges_list)
328 a8083063 Iustin Pop
329 a8083063 Iustin Pop
  # instance  --------------------------
330 a8083063 Iustin Pop
331 3ecf6786 Iustin Pop
  @staticmethod
332 3ecf6786 Iustin Pop
  def perspective_instance_os_add(params):
333 3ecf6786 Iustin Pop
    """Install an OS on a given instance.
334 3ecf6786 Iustin Pop
335 3ecf6786 Iustin Pop
    """
336 a8083063 Iustin Pop
    inst_s, os_disk, swap_disk = params
337 319856a9 Michael Hanselmann
    inst = objects.Instance.FromDict(inst_s)
338 a8083063 Iustin Pop
    return backend.AddOSToInstance(inst, os_disk, swap_disk)
339 a8083063 Iustin Pop
340 3ecf6786 Iustin Pop
  @staticmethod
341 decd5f45 Iustin Pop
  def perspective_instance_run_rename(params):
342 decd5f45 Iustin Pop
    """Runs the OS rename script for an instance.
343 decd5f45 Iustin Pop
344 decd5f45 Iustin Pop
    """
345 decd5f45 Iustin Pop
    inst_s, old_name, os_disk, swap_disk = params
346 319856a9 Michael Hanselmann
    inst = objects.Instance.FromDict(inst_s)
347 decd5f45 Iustin Pop
    return backend.RunRenameInstance(inst, old_name, os_disk, swap_disk)
348 decd5f45 Iustin Pop
349 decd5f45 Iustin Pop
  @staticmethod
350 3ecf6786 Iustin Pop
  def perspective_instance_os_import(params):
351 3ecf6786 Iustin Pop
    """Run the import function of an OS onto a given instance.
352 3ecf6786 Iustin Pop
353 3ecf6786 Iustin Pop
    """
354 a8083063 Iustin Pop
    inst_s, os_disk, swap_disk, src_node, src_image = params
355 319856a9 Michael Hanselmann
    inst = objects.Instance.FromDict(inst_s)
356 a8083063 Iustin Pop
    return backend.ImportOSIntoInstance(inst, os_disk, swap_disk,
357 a8083063 Iustin Pop
                                        src_node, src_image)
358 a8083063 Iustin Pop
359 3ecf6786 Iustin Pop
  @staticmethod
360 3ecf6786 Iustin Pop
  def perspective_instance_shutdown(params):
361 3ecf6786 Iustin Pop
    """Shutdown an instance.
362 3ecf6786 Iustin Pop
363 3ecf6786 Iustin Pop
    """
364 319856a9 Michael Hanselmann
    instance = objects.Instance.FromDict(params[0])
365 a8083063 Iustin Pop
    return backend.ShutdownInstance(instance)
366 a8083063 Iustin Pop
367 3ecf6786 Iustin Pop
  @staticmethod
368 3ecf6786 Iustin Pop
  def perspective_instance_start(params):
369 3ecf6786 Iustin Pop
    """Start an instance.
370 3ecf6786 Iustin Pop
371 3ecf6786 Iustin Pop
    """
372 319856a9 Michael Hanselmann
    instance = objects.Instance.FromDict(params[0])
373 a8083063 Iustin Pop
    extra_args = params[1]
374 a8083063 Iustin Pop
    return backend.StartInstance(instance, extra_args)
375 a8083063 Iustin Pop
376 3ecf6786 Iustin Pop
  @staticmethod
377 2a10865c Iustin Pop
  def perspective_instance_migrate(params):
378 2a10865c Iustin Pop
    """Migrates an instance.
379 2a10865c Iustin Pop
380 2a10865c Iustin Pop
    """
381 2a10865c Iustin Pop
    instance, target, live = params
382 2a10865c Iustin Pop
    return backend.MigrateInstance(instance, target, live)
383 2a10865c Iustin Pop
384 2a10865c Iustin Pop
  @staticmethod
385 007a2f3e Alexander Schreiber
  def perspective_instance_reboot(params):
386 007a2f3e Alexander Schreiber
    """Reboot an instance.
387 007a2f3e Alexander Schreiber
388 007a2f3e Alexander Schreiber
    """
389 007a2f3e Alexander Schreiber
    instance = objects.Instance.FromDict(params[0])
390 007a2f3e Alexander Schreiber
    reboot_type = params[1]
391 007a2f3e Alexander Schreiber
    extra_args = params[2]
392 007a2f3e Alexander Schreiber
    return backend.RebootInstance(instance, reboot_type, extra_args)
393 007a2f3e Alexander Schreiber
394 007a2f3e Alexander Schreiber
  @staticmethod
395 3ecf6786 Iustin Pop
  def perspective_instance_info(params):
396 3ecf6786 Iustin Pop
    """Query instance information.
397 3ecf6786 Iustin Pop
398 3ecf6786 Iustin Pop
    """
399 a8083063 Iustin Pop
    return backend.GetInstanceInfo(params[0])
400 a8083063 Iustin Pop
401 3ecf6786 Iustin Pop
  @staticmethod
402 3ecf6786 Iustin Pop
  def perspective_all_instances_info(params):
403 3ecf6786 Iustin Pop
    """Query information about all instances.
404 3ecf6786 Iustin Pop
405 3ecf6786 Iustin Pop
    """
406 a8083063 Iustin Pop
    return backend.GetAllInstancesInfo()
407 a8083063 Iustin Pop
408 3ecf6786 Iustin Pop
  @staticmethod
409 3ecf6786 Iustin Pop
  def perspective_instance_list(params):
410 3ecf6786 Iustin Pop
    """Query the list of running instances.
411 3ecf6786 Iustin Pop
412 3ecf6786 Iustin Pop
    """
413 a8083063 Iustin Pop
    return backend.GetInstanceList()
414 a8083063 Iustin Pop
415 a8083063 Iustin Pop
  # node --------------------------
416 a8083063 Iustin Pop
417 3ecf6786 Iustin Pop
  @staticmethod
418 16abfbc2 Alexander Schreiber
  def perspective_node_tcp_ping(params):
419 16abfbc2 Alexander Schreiber
    """Do a TcpPing on the remote node.
420 16abfbc2 Alexander Schreiber
421 16abfbc2 Alexander Schreiber
    """
422 b15d625f Iustin Pop
    return utils.TcpPing(params[1], params[2], timeout=params[3],
423 b15d625f Iustin Pop
                         live_port_needed=params[4], source=params[0])
424 16abfbc2 Alexander Schreiber
425 16abfbc2 Alexander Schreiber
  @staticmethod
426 3ecf6786 Iustin Pop
  def perspective_node_info(params):
427 3ecf6786 Iustin Pop
    """Query node information.
428 3ecf6786 Iustin Pop
429 3ecf6786 Iustin Pop
    """
430 a8083063 Iustin Pop
    vgname = params[0]
431 a8083063 Iustin Pop
    return backend.GetNodeInfo(vgname)
432 a8083063 Iustin Pop
433 3ecf6786 Iustin Pop
  @staticmethod
434 3ecf6786 Iustin Pop
  def perspective_node_add(params):
435 3ecf6786 Iustin Pop
    """Complete the registration of this node in the cluster.
436 3ecf6786 Iustin Pop
437 3ecf6786 Iustin Pop
    """
438 a8083063 Iustin Pop
    return backend.AddNode(params[0], params[1], params[2],
439 a8083063 Iustin Pop
                           params[3], params[4], params[5])
440 a8083063 Iustin Pop
441 3ecf6786 Iustin Pop
  @staticmethod
442 3ecf6786 Iustin Pop
  def perspective_node_verify(params):
443 3ecf6786 Iustin Pop
    """Run a verify sequence on this node.
444 3ecf6786 Iustin Pop
445 3ecf6786 Iustin Pop
    """
446 a8083063 Iustin Pop
    return backend.VerifyNode(params[0])
447 a8083063 Iustin Pop
448 3ecf6786 Iustin Pop
  @staticmethod
449 3ecf6786 Iustin Pop
  def perspective_node_start_master(params):
450 3ecf6786 Iustin Pop
    """Promote this node to master status.
451 3ecf6786 Iustin Pop
452 3ecf6786 Iustin Pop
    """
453 a8083063 Iustin Pop
    return backend.StartMaster()
454 a8083063 Iustin Pop
455 3ecf6786 Iustin Pop
  @staticmethod
456 3ecf6786 Iustin Pop
  def perspective_node_stop_master(params):
457 3ecf6786 Iustin Pop
    """Demote this node from master status.
458 3ecf6786 Iustin Pop
459 3ecf6786 Iustin Pop
    """
460 a8083063 Iustin Pop
    return backend.StopMaster()
461 a8083063 Iustin Pop
462 3ecf6786 Iustin Pop
  @staticmethod
463 3ecf6786 Iustin Pop
  def perspective_node_leave_cluster(params):
464 3ecf6786 Iustin Pop
    """Cleanup after leaving a cluster.
465 3ecf6786 Iustin Pop
466 3ecf6786 Iustin Pop
    """
467 a8083063 Iustin Pop
    return backend.LeaveCluster()
468 a8083063 Iustin Pop
469 3ecf6786 Iustin Pop
  @staticmethod
470 3ecf6786 Iustin Pop
  def perspective_node_volumes(params):
471 3ecf6786 Iustin Pop
    """Query the list of all logical volume groups.
472 3ecf6786 Iustin Pop
473 3ecf6786 Iustin Pop
    """
474 dcb93971 Michael Hanselmann
    return backend.NodeVolumes()
475 dcb93971 Michael Hanselmann
476 a8083063 Iustin Pop
  # cluster --------------------------
477 a8083063 Iustin Pop
478 3ecf6786 Iustin Pop
  @staticmethod
479 3ecf6786 Iustin Pop
  def perspective_version(params):
480 3ecf6786 Iustin Pop
    """Query version information.
481 3ecf6786 Iustin Pop
482 3ecf6786 Iustin Pop
    """
483 a8083063 Iustin Pop
    return constants.PROTOCOL_VERSION
484 a8083063 Iustin Pop
485 3ecf6786 Iustin Pop
  @staticmethod
486 3ecf6786 Iustin Pop
  def perspective_upload_file(params):
487 3ecf6786 Iustin Pop
    """Upload a file.
488 3ecf6786 Iustin Pop
489 3ecf6786 Iustin Pop
    Note that the backend implementation imposes strict rules on which
490 3ecf6786 Iustin Pop
    files are accepted.
491 3ecf6786 Iustin Pop
492 3ecf6786 Iustin Pop
    """
493 a8083063 Iustin Pop
    return backend.UploadFile(*params)
494 a8083063 Iustin Pop
495 a8083063 Iustin Pop
496 a8083063 Iustin Pop
  # os -----------------------
497 a8083063 Iustin Pop
498 3ecf6786 Iustin Pop
  @staticmethod
499 3ecf6786 Iustin Pop
  def perspective_os_diagnose(params):
500 3ecf6786 Iustin Pop
    """Query detailed information about existing OSes.
501 3ecf6786 Iustin Pop
502 3ecf6786 Iustin Pop
    """
503 4e679f11 Guido Trotter
    return [os.ToDict() for os in backend.DiagnoseOS()]
504 a8083063 Iustin Pop
505 3ecf6786 Iustin Pop
  @staticmethod
506 3ecf6786 Iustin Pop
  def perspective_os_get(params):
507 3ecf6786 Iustin Pop
    """Query information about a given OS.
508 3ecf6786 Iustin Pop
509 3ecf6786 Iustin Pop
    """
510 a8083063 Iustin Pop
    name = params[0]
511 a8083063 Iustin Pop
    try:
512 dfa96ded Guido Trotter
      os_obj = backend.OSFromDisk(name)
513 a8083063 Iustin Pop
    except errors.InvalidOS, err:
514 dfa96ded Guido Trotter
      os_obj = objects.OS.FromInvalidOS(err)
515 dfa96ded Guido Trotter
    return os_obj.ToDict()
516 a8083063 Iustin Pop
517 a8083063 Iustin Pop
  # hooks -----------------------
518 a8083063 Iustin Pop
519 3ecf6786 Iustin Pop
  @staticmethod
520 3ecf6786 Iustin Pop
  def perspective_hooks_runner(params):
521 3ecf6786 Iustin Pop
    """Run hook scripts.
522 3ecf6786 Iustin Pop
523 3ecf6786 Iustin Pop
    """
524 a8083063 Iustin Pop
    hpath, phase, env = params
525 a8083063 Iustin Pop
    hr = backend.HooksRunner()
526 a8083063 Iustin Pop
    return hr.RunHooks(hpath, phase, env)
527 a8083063 Iustin Pop
528 8d528b7c Iustin Pop
  # iallocator -----------------
529 8d528b7c Iustin Pop
530 8d528b7c Iustin Pop
  @staticmethod
531 8d528b7c Iustin Pop
  def perspective_iallocator_runner(params):
532 8d528b7c Iustin Pop
    """Run an iallocator script.
533 8d528b7c Iustin Pop
534 8d528b7c Iustin Pop
    """
535 8d528b7c Iustin Pop
    name, idata = params
536 8d528b7c Iustin Pop
    iar = backend.IAllocatorRunner()
537 8d528b7c Iustin Pop
    return iar.Run(name, idata)
538 8d528b7c Iustin Pop
539 06009e27 Iustin Pop
  # test -----------------------
540 06009e27 Iustin Pop
541 06009e27 Iustin Pop
  @staticmethod
542 06009e27 Iustin Pop
  def perspective_test_delay(params):
543 06009e27 Iustin Pop
    """Run test delay.
544 06009e27 Iustin Pop
545 06009e27 Iustin Pop
    """
546 06009e27 Iustin Pop
    duration = params[0]
547 06009e27 Iustin Pop
    return utils.TestDelay(duration)
548 06009e27 Iustin Pop
549 a5d7fb43 Manuel Franceschini
  @staticmethod
550 a5d7fb43 Manuel Franceschini
  def perspective_file_storage_dir_create(params):
551 a5d7fb43 Manuel Franceschini
    """Create the file storage directory.
552 a5d7fb43 Manuel Franceschini
553 a5d7fb43 Manuel Franceschini
    """
554 a5d7fb43 Manuel Franceschini
    file_storage_dir = params[0]
555 a5d7fb43 Manuel Franceschini
    return backend.CreateFileStorageDir(file_storage_dir)
556 a5d7fb43 Manuel Franceschini
557 a5d7fb43 Manuel Franceschini
  @staticmethod
558 a5d7fb43 Manuel Franceschini
  def perspective_file_storage_dir_remove(params):
559 a5d7fb43 Manuel Franceschini
    """Remove the file storage directory.
560 a5d7fb43 Manuel Franceschini
561 a5d7fb43 Manuel Franceschini
    """
562 a5d7fb43 Manuel Franceschini
    file_storage_dir = params[0]
563 a5d7fb43 Manuel Franceschini
    return backend.RemoveFileStorageDir(file_storage_dir)
564 a5d7fb43 Manuel Franceschini
565 a5d7fb43 Manuel Franceschini
  @staticmethod
566 a5d7fb43 Manuel Franceschini
  def perspective_file_storage_dir_rename(params):
567 a5d7fb43 Manuel Franceschini
    """Rename the file storage directory.
568 a5d7fb43 Manuel Franceschini
569 a5d7fb43 Manuel Franceschini
    """
570 a5d7fb43 Manuel Franceschini
    old_file_storage_dir = params[0]
571 a5d7fb43 Manuel Franceschini
    new_file_storage_dir = params[1]
572 a5d7fb43 Manuel Franceschini
    return backend.RenameFileStorageDir(old_file_storage_dir,
573 a5d7fb43 Manuel Franceschini
                                        new_file_storage_dir)
574 a5d7fb43 Manuel Franceschini
575 a8083063 Iustin Pop
576 a8083063 Iustin Pop
def ParseOptions():
577 a8083063 Iustin Pop
  """Parse the command line options.
578 a8083063 Iustin Pop
579 a8083063 Iustin Pop
  Returns:
580 a8083063 Iustin Pop
    (options, args) as from OptionParser.parse_args()
581 a8083063 Iustin Pop
582 a8083063 Iustin Pop
  """
583 a8083063 Iustin Pop
  parser = OptionParser(description="Ganeti node daemon",
584 a8083063 Iustin Pop
                        usage="%prog [-f] [-d]",
585 a8083063 Iustin Pop
                        version="%%prog (ganeti) %s" %
586 a8083063 Iustin Pop
                        constants.RELEASE_VERSION)
587 a8083063 Iustin Pop
588 a8083063 Iustin Pop
  parser.add_option("-f", "--foreground", dest="fork",
589 a8083063 Iustin Pop
                    help="Don't detach from the current terminal",
590 a8083063 Iustin Pop
                    default=True, action="store_false")
591 a8083063 Iustin Pop
  parser.add_option("-d", "--debug", dest="debug",
592 a8083063 Iustin Pop
                    help="Enable some debug messages",
593 a8083063 Iustin Pop
                    default=False, action="store_true")
594 a8083063 Iustin Pop
  options, args = parser.parse_args()
595 a8083063 Iustin Pop
  return options, args
596 a8083063 Iustin Pop
597 a8083063 Iustin Pop
598 a8083063 Iustin Pop
def main():
599 3ecf6786 Iustin Pop
  """Main function for the node daemon.
600 3ecf6786 Iustin Pop
601 3ecf6786 Iustin Pop
  """
602 a8083063 Iustin Pop
  options, args = ParseOptions()
603 f362096f Iustin Pop
  utils.debug = options.debug
604 a8083063 Iustin Pop
  for fname in (constants.SSL_CERT_FILE,):
605 a8083063 Iustin Pop
    if not os.path.isfile(fname):
606 a8083063 Iustin Pop
      print "config %s not there, will not run." % fname
607 a8083063 Iustin Pop
      sys.exit(5)
608 a8083063 Iustin Pop
609 a8083063 Iustin Pop
  try:
610 a8083063 Iustin Pop
    ss = ssconf.SimpleStore()
611 a8083063 Iustin Pop
    port = ss.GetNodeDaemonPort()
612 a8083063 Iustin Pop
    pwdata = ss.GetNodeDaemonPassword()
613 a8083063 Iustin Pop
  except errors.ConfigurationError, err:
614 a8083063 Iustin Pop
    print "Cluster configuration incomplete: '%s'" % str(err)
615 a8083063 Iustin Pop
    sys.exit(5)
616 a8083063 Iustin Pop
617 195c7f91 Iustin Pop
  # create the various SUB_RUN_DIRS, if not existing, so that we handle the
618 195c7f91 Iustin Pop
  # situation where RUN_DIR is tmpfs
619 195c7f91 Iustin Pop
  for dir_name in constants.SUB_RUN_DIRS:
620 195c7f91 Iustin Pop
    if not os.path.exists(dir_name):
621 195c7f91 Iustin Pop
      try:
622 195c7f91 Iustin Pop
        os.mkdir(dir_name, 0755)
623 195c7f91 Iustin Pop
      except EnvironmentError, err:
624 195c7f91 Iustin Pop
        if err.errno != errno.EEXIST:
625 195c7f91 Iustin Pop
          print ("Node setup wrong, cannot create directory %s: %s" %
626 195c7f91 Iustin Pop
                 (dir_name, err))
627 195c7f91 Iustin Pop
          sys.exit(5)
628 195c7f91 Iustin Pop
    if not os.path.isdir(dir_name):
629 195c7f91 Iustin Pop
      print ("Node setup wrong, %s is not a directory" % dir_name)
630 195c7f91 Iustin Pop
      sys.exit(5)
631 0214b0c0 Iustin Pop
632 a8083063 Iustin Pop
  # become a daemon
633 a8083063 Iustin Pop
  if options.fork:
634 8f765069 Iustin Pop
    utils.Daemonize(logfile=constants.LOG_NODESERVER)
635 a8083063 Iustin Pop
636 ff5fac04 Iustin Pop
  logger.SetupDaemon(logfile=constants.LOG_NODESERVER, debug=options.debug,
637 ff5fac04 Iustin Pop
                     stderr_logging=not options.fork)
638 c89189b1 Iustin Pop
  logging.info("ganeti node daemon startup")
639 a8083063 Iustin Pop
640 3b3db8fd Guido Trotter
  global _EXIT_GANETI_NODED
641 3b3db8fd Guido Trotter
642 81010134 Iustin Pop
  httpd = BaseHTTPServer.HTTPServer(('', port), ServerObject)
643 3b3db8fd Guido Trotter
  while (not _EXIT_GANETI_NODED):
644 3b3db8fd Guido Trotter
    httpd.handle_request()
645 a8083063 Iustin Pop
646 a8083063 Iustin Pop
647 3ecf6786 Iustin Pop
if __name__ == '__main__':
648 a8083063 Iustin Pop
  main()