Statistics
| Branch: | Tag: | Revision:

root / daemons / ganeti-noded @ 62c9ec92

History | View | Annotate | Download (18 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 761ce945 Guido Trotter
import SocketServer
31 0214b0c0 Iustin Pop
import errno
32 c89189b1 Iustin Pop
import logging
33 84b58db2 Michael Hanselmann
import signal
34 a8083063 Iustin Pop
35 a8083063 Iustin Pop
from optparse import OptionParser
36 a8083063 Iustin Pop
37 a8083063 Iustin Pop
from ganeti import backend
38 a8083063 Iustin Pop
from ganeti import logger
39 a8083063 Iustin Pop
from ganeti import constants
40 a8083063 Iustin Pop
from ganeti import objects
41 a8083063 Iustin Pop
from ganeti import errors
42 25d6d12a Michael Hanselmann
from ganeti import jstore
43 1df6506c Michael Hanselmann
from ganeti import http
44 16abfbc2 Alexander Schreiber
from ganeti import utils
45 a8083063 Iustin Pop
46 a8083063 Iustin Pop
47 25d6d12a Michael Hanselmann
queue_lock = None
48 25d6d12a Michael Hanselmann
49 25d6d12a Michael Hanselmann
50 7f30777b Michael Hanselmann
def _RequireJobQueueLock(fn):
51 7f30777b Michael Hanselmann
  """Decorator for job queue manipulating functions.
52 7f30777b Michael Hanselmann
53 7f30777b Michael Hanselmann
  """
54 8785cb30 Michael Hanselmann
  QUEUE_LOCK_TIMEOUT = 10
55 8785cb30 Michael Hanselmann
56 7f30777b Michael Hanselmann
  def wrapper(*args, **kwargs):
57 7f30777b Michael Hanselmann
    # Locking in exclusive, blocking mode because there could be several
58 506cff12 Michael Hanselmann
    # children running at the same time. Waiting up to 10 seconds.
59 8785cb30 Michael Hanselmann
    queue_lock.Exclusive(blocking=True, timeout=QUEUE_LOCK_TIMEOUT)
60 7f30777b Michael Hanselmann
    try:
61 7f30777b Michael Hanselmann
      return fn(*args, **kwargs)
62 7f30777b Michael Hanselmann
    finally:
63 7f30777b Michael Hanselmann
      queue_lock.Unlock()
64 8785cb30 Michael Hanselmann
65 7f30777b Michael Hanselmann
  return wrapper
66 7f30777b Michael Hanselmann
67 7f30777b Michael Hanselmann
68 1df6506c Michael Hanselmann
class NodeDaemonRequestHandler(http.HTTPRequestHandler):
69 3ecf6786 Iustin Pop
  """The server implementation.
70 3ecf6786 Iustin Pop
71 3ecf6786 Iustin Pop
  This class holds all methods exposed over the RPC interface.
72 3ecf6786 Iustin Pop
73 3ecf6786 Iustin Pop
  """
74 1df6506c Michael Hanselmann
  def HandleRequest(self):
75 1df6506c Michael Hanselmann
    """Handle a request.
76 a8083063 Iustin Pop
77 098c0958 Michael Hanselmann
    """
78 1df6506c Michael Hanselmann
    if self.command.upper() != "PUT":
79 1df6506c Michael Hanselmann
      raise http.HTTPBadRequest()
80 1df6506c Michael Hanselmann
81 81010134 Iustin Pop
    path = self.path
82 81010134 Iustin Pop
    if path.startswith("/"):
83 81010134 Iustin Pop
      path = path[1:]
84 81010134 Iustin Pop
85 1df6506c Michael Hanselmann
    method = getattr(self, "perspective_%s" % path, None)
86 1df6506c Michael Hanselmann
    if method is None:
87 1df6506c Michael Hanselmann
      raise httperror.HTTPNotFound()
88 a8083063 Iustin Pop
89 81010134 Iustin Pop
    try:
90 aa9075c5 Michael Hanselmann
      try:
91 aa9075c5 Michael Hanselmann
        return method(self.post_data)
92 aa9075c5 Michael Hanselmann
      except:
93 aa9075c5 Michael Hanselmann
        logging.exception("Error in RPC call")
94 aa9075c5 Michael Hanselmann
        raise
95 9ae49f27 Guido Trotter
    except errors.QuitGanetiException, err:
96 84b58db2 Michael Hanselmann
      # Tell parent to quit
97 84b58db2 Michael Hanselmann
      os.kill(self.server.noded_pid, signal.SIGTERM)
98 a8083063 Iustin Pop
99 a8083063 Iustin Pop
  # the new block devices  --------------------------
100 a8083063 Iustin Pop
101 3ecf6786 Iustin Pop
  @staticmethod
102 3ecf6786 Iustin Pop
  def perspective_blockdev_create(params):
103 3ecf6786 Iustin Pop
    """Create a block device.
104 3ecf6786 Iustin Pop
105 3ecf6786 Iustin Pop
    """
106 3f78eef2 Iustin Pop
    bdev_s, size, owner, on_primary, info = params
107 319856a9 Michael Hanselmann
    bdev = objects.Disk.FromDict(bdev_s)
108 a8083063 Iustin Pop
    if bdev is None:
109 a8083063 Iustin Pop
      raise ValueError("can't unserialize data!")
110 3f78eef2 Iustin Pop
    return backend.CreateBlockDevice(bdev, size, owner, on_primary, info)
111 a8083063 Iustin Pop
112 3ecf6786 Iustin Pop
  @staticmethod
113 3ecf6786 Iustin Pop
  def perspective_blockdev_remove(params):
114 3ecf6786 Iustin Pop
    """Remove a block device.
115 3ecf6786 Iustin Pop
116 3ecf6786 Iustin Pop
    """
117 a8083063 Iustin Pop
    bdev_s = params[0]
118 319856a9 Michael Hanselmann
    bdev = objects.Disk.FromDict(bdev_s)
119 a8083063 Iustin Pop
    return backend.RemoveBlockDevice(bdev)
120 a8083063 Iustin Pop
121 3ecf6786 Iustin Pop
  @staticmethod
122 f3e513ad Iustin Pop
  def perspective_blockdev_rename(params):
123 f3e513ad Iustin Pop
    """Remove a block device.
124 f3e513ad Iustin Pop
125 f3e513ad Iustin Pop
    """
126 f3e513ad Iustin Pop
    devlist = [(objects.Disk.FromDict(ds), uid) for ds, uid in params]
127 f3e513ad Iustin Pop
    return backend.RenameBlockDevices(devlist)
128 f3e513ad Iustin Pop
129 f3e513ad Iustin Pop
  @staticmethod
130 3ecf6786 Iustin Pop
  def perspective_blockdev_assemble(params):
131 3ecf6786 Iustin Pop
    """Assemble a block device.
132 3ecf6786 Iustin Pop
133 3ecf6786 Iustin Pop
    """
134 3f78eef2 Iustin Pop
    bdev_s, owner, on_primary = params
135 319856a9 Michael Hanselmann
    bdev = objects.Disk.FromDict(bdev_s)
136 a8083063 Iustin Pop
    if bdev is None:
137 a8083063 Iustin Pop
      raise ValueError("can't unserialize data!")
138 3f78eef2 Iustin Pop
    return backend.AssembleBlockDevice(bdev, owner, on_primary)
139 a8083063 Iustin Pop
140 3ecf6786 Iustin Pop
  @staticmethod
141 3ecf6786 Iustin Pop
  def perspective_blockdev_shutdown(params):
142 3ecf6786 Iustin Pop
    """Shutdown a block device.
143 3ecf6786 Iustin Pop
144 3ecf6786 Iustin Pop
    """
145 a8083063 Iustin Pop
    bdev_s = params[0]
146 319856a9 Michael Hanselmann
    bdev = objects.Disk.FromDict(bdev_s)
147 a8083063 Iustin Pop
    if bdev is None:
148 a8083063 Iustin Pop
      raise ValueError("can't unserialize data!")
149 a8083063 Iustin Pop
    return backend.ShutdownBlockDevice(bdev)
150 a8083063 Iustin Pop
151 3ecf6786 Iustin Pop
  @staticmethod
152 153d9724 Iustin Pop
  def perspective_blockdev_addchildren(params):
153 3ecf6786 Iustin Pop
    """Add a child to a mirror device.
154 3ecf6786 Iustin Pop
155 3ecf6786 Iustin Pop
    Note: this is only valid for mirror devices. It's the caller's duty
156 3ecf6786 Iustin Pop
    to send a correct disk, otherwise we raise an error.
157 3ecf6786 Iustin Pop
158 3ecf6786 Iustin Pop
    """
159 a8083063 Iustin Pop
    bdev_s, ndev_s = params
160 319856a9 Michael Hanselmann
    bdev = objects.Disk.FromDict(bdev_s)
161 153d9724 Iustin Pop
    ndevs = [objects.Disk.FromDict(disk_s) for disk_s in ndev_s]
162 153d9724 Iustin Pop
    if bdev is None or ndevs.count(None) > 0:
163 a8083063 Iustin Pop
      raise ValueError("can't unserialize data!")
164 153d9724 Iustin Pop
    return backend.MirrorAddChildren(bdev, ndevs)
165 a8083063 Iustin Pop
166 3ecf6786 Iustin Pop
  @staticmethod
167 153d9724 Iustin Pop
  def perspective_blockdev_removechildren(params):
168 3ecf6786 Iustin Pop
    """Remove a child from a mirror device.
169 3ecf6786 Iustin Pop
170 3ecf6786 Iustin Pop
    This is only valid for mirror devices, of course. It's the callers
171 3ecf6786 Iustin Pop
    duty to send a correct disk, otherwise we raise an error.
172 3ecf6786 Iustin Pop
173 3ecf6786 Iustin Pop
    """
174 a8083063 Iustin Pop
    bdev_s, ndev_s = params
175 319856a9 Michael Hanselmann
    bdev = objects.Disk.FromDict(bdev_s)
176 153d9724 Iustin Pop
    ndevs = [objects.Disk.FromDict(disk_s) for disk_s in ndev_s]
177 153d9724 Iustin Pop
    if bdev is None or ndevs.count(None) > 0:
178 a8083063 Iustin Pop
      raise ValueError("can't unserialize data!")
179 153d9724 Iustin Pop
    return backend.MirrorRemoveChildren(bdev, ndevs)
180 a8083063 Iustin Pop
181 3ecf6786 Iustin Pop
  @staticmethod
182 3ecf6786 Iustin Pop
  def perspective_blockdev_getmirrorstatus(params):
183 3ecf6786 Iustin Pop
    """Return the mirror status for a list of disks.
184 3ecf6786 Iustin Pop
185 3ecf6786 Iustin Pop
    """
186 319856a9 Michael Hanselmann
    disks = [objects.Disk.FromDict(dsk_s)
187 a8083063 Iustin Pop
            for dsk_s in params]
188 a8083063 Iustin Pop
    return backend.GetMirrorStatus(disks)
189 a8083063 Iustin Pop
190 3ecf6786 Iustin Pop
  @staticmethod
191 3ecf6786 Iustin Pop
  def perspective_blockdev_find(params):
192 3ecf6786 Iustin Pop
    """Expose the FindBlockDevice functionality for a disk.
193 3ecf6786 Iustin Pop
194 3ecf6786 Iustin Pop
    This will try to find but not activate a disk.
195 3ecf6786 Iustin Pop
196 3ecf6786 Iustin Pop
    """
197 319856a9 Michael Hanselmann
    disk = objects.Disk.FromDict(params[0])
198 a8083063 Iustin Pop
    return backend.FindBlockDevice(disk)
199 a8083063 Iustin Pop
200 3ecf6786 Iustin Pop
  @staticmethod
201 3ecf6786 Iustin Pop
  def perspective_blockdev_snapshot(params):
202 3ecf6786 Iustin Pop
    """Create a snapshot device.
203 3ecf6786 Iustin Pop
204 3ecf6786 Iustin Pop
    Note that this is only valid for LVM disks, if we get passed
205 3ecf6786 Iustin Pop
    something else we raise an exception. The snapshot device can be
206 3ecf6786 Iustin Pop
    remove by calling the generic block device remove call.
207 3ecf6786 Iustin Pop
208 3ecf6786 Iustin Pop
    """
209 319856a9 Michael Hanselmann
    cfbd = objects.Disk.FromDict(params[0])
210 a8083063 Iustin Pop
    return backend.SnapshotBlockDevice(cfbd)
211 a8083063 Iustin Pop
212 4c8ba8b3 Iustin Pop
  @staticmethod
213 4c8ba8b3 Iustin Pop
  def perspective_blockdev_grow(params):
214 4c8ba8b3 Iustin Pop
    """Grow a stack of devices.
215 4c8ba8b3 Iustin Pop
216 4c8ba8b3 Iustin Pop
    """
217 4c8ba8b3 Iustin Pop
    cfbd = objects.Disk.FromDict(params[0])
218 4c8ba8b3 Iustin Pop
    amount = params[1]
219 4c8ba8b3 Iustin Pop
    return backend.GrowBlockDevice(cfbd, amount)
220 4c8ba8b3 Iustin Pop
221 d61cbe76 Iustin Pop
  @staticmethod
222 d61cbe76 Iustin Pop
  def perspective_blockdev_close(params):
223 d61cbe76 Iustin Pop
    """Closes the given block devices.
224 d61cbe76 Iustin Pop
225 d61cbe76 Iustin Pop
    """
226 d61cbe76 Iustin Pop
    disks = [objects.Disk.FromDict(cf) for cf in params]
227 d61cbe76 Iustin Pop
    return backend.CloseBlockDevices(disks)
228 d61cbe76 Iustin Pop
229 a8083063 Iustin Pop
  # export/import  --------------------------
230 a8083063 Iustin Pop
231 3ecf6786 Iustin Pop
  @staticmethod
232 3ecf6786 Iustin Pop
  def perspective_snapshot_export(params):
233 3ecf6786 Iustin Pop
    """Export a given snapshot.
234 3ecf6786 Iustin Pop
235 3ecf6786 Iustin Pop
    """
236 319856a9 Michael Hanselmann
    disk = objects.Disk.FromDict(params[0])
237 a8083063 Iustin Pop
    dest_node = params[1]
238 319856a9 Michael Hanselmann
    instance = objects.Instance.FromDict(params[2])
239 62c9ec92 Iustin Pop
    cluster_name = params[3]
240 62c9ec92 Iustin Pop
    return backend.ExportSnapshot(disk, dest_node, instance, cluster_name)
241 3ecf6786 Iustin Pop
242 3ecf6786 Iustin Pop
  @staticmethod
243 3ecf6786 Iustin Pop
  def perspective_finalize_export(params):
244 3ecf6786 Iustin Pop
    """Expose the finalize export functionality.
245 a8083063 Iustin Pop
246 3ecf6786 Iustin Pop
    """
247 319856a9 Michael Hanselmann
    instance = objects.Instance.FromDict(params[0])
248 319856a9 Michael Hanselmann
    snap_disks = [objects.Disk.FromDict(str_data)
249 a8083063 Iustin Pop
                  for str_data in params[1]]
250 a8083063 Iustin Pop
    return backend.FinalizeExport(instance, snap_disks)
251 a8083063 Iustin Pop
252 3ecf6786 Iustin Pop
  @staticmethod
253 3ecf6786 Iustin Pop
  def perspective_export_info(params):
254 3ecf6786 Iustin Pop
    """Query information about an existing export on this node.
255 3ecf6786 Iustin Pop
256 3ecf6786 Iustin Pop
    The given path may not contain an export, in which case we return
257 3ecf6786 Iustin Pop
    None.
258 3ecf6786 Iustin Pop
259 3ecf6786 Iustin Pop
    """
260 3ecf6786 Iustin Pop
    path = params[0]
261 3ecf6786 Iustin Pop
    einfo = backend.ExportInfo(path)
262 a8083063 Iustin Pop
    if einfo is None:
263 a8083063 Iustin Pop
      return einfo
264 a8083063 Iustin Pop
    return einfo.Dumps()
265 a8083063 Iustin Pop
266 3ecf6786 Iustin Pop
  @staticmethod
267 3ecf6786 Iustin Pop
  def perspective_export_list(params):
268 3ecf6786 Iustin Pop
    """List the available exports on this node.
269 3ecf6786 Iustin Pop
270 3ecf6786 Iustin Pop
    Note that as opposed to export_info, which may query data about an
271 3ecf6786 Iustin Pop
    export in any path, this only queries the standard Ganeti path
272 3ecf6786 Iustin Pop
    (constants.EXPORT_DIR).
273 3ecf6786 Iustin Pop
274 3ecf6786 Iustin Pop
    """
275 a8083063 Iustin Pop
    return backend.ListExports()
276 a8083063 Iustin Pop
277 3ecf6786 Iustin Pop
  @staticmethod
278 3ecf6786 Iustin Pop
  def perspective_export_remove(params):
279 3ecf6786 Iustin Pop
    """Remove an export.
280 3ecf6786 Iustin Pop
281 3ecf6786 Iustin Pop
    """
282 a8083063 Iustin Pop
    export = params[0]
283 a8083063 Iustin Pop
    return backend.RemoveExport(export)
284 a8083063 Iustin Pop
285 a8083063 Iustin Pop
  # volume  --------------------------
286 a8083063 Iustin Pop
287 3ecf6786 Iustin Pop
  @staticmethod
288 3ecf6786 Iustin Pop
  def perspective_volume_list(params):
289 3ecf6786 Iustin Pop
    """Query the list of logical volumes in a given volume group.
290 3ecf6786 Iustin Pop
291 3ecf6786 Iustin Pop
    """
292 a8083063 Iustin Pop
    vgname = params[0]
293 a8083063 Iustin Pop
    return backend.GetVolumeList(vgname)
294 a8083063 Iustin Pop
295 3ecf6786 Iustin Pop
  @staticmethod
296 3ecf6786 Iustin Pop
  def perspective_vg_list(params):
297 3ecf6786 Iustin Pop
    """Query the list of volume groups.
298 3ecf6786 Iustin Pop
299 3ecf6786 Iustin Pop
    """
300 a8083063 Iustin Pop
    return backend.ListVolumeGroups()
301 a8083063 Iustin Pop
302 a8083063 Iustin Pop
  # bridge  --------------------------
303 a8083063 Iustin Pop
304 3ecf6786 Iustin Pop
  @staticmethod
305 3ecf6786 Iustin Pop
  def perspective_bridges_exist(params):
306 3ecf6786 Iustin Pop
    """Check if all bridges given exist on this node.
307 3ecf6786 Iustin Pop
308 3ecf6786 Iustin Pop
    """
309 a8083063 Iustin Pop
    bridges_list = params[0]
310 a8083063 Iustin Pop
    return backend.BridgesExist(bridges_list)
311 a8083063 Iustin Pop
312 a8083063 Iustin Pop
  # instance  --------------------------
313 a8083063 Iustin Pop
314 3ecf6786 Iustin Pop
  @staticmethod
315 3ecf6786 Iustin Pop
  def perspective_instance_os_add(params):
316 3ecf6786 Iustin Pop
    """Install an OS on a given instance.
317 3ecf6786 Iustin Pop
318 3ecf6786 Iustin Pop
    """
319 a8083063 Iustin Pop
    inst_s, os_disk, swap_disk = params
320 319856a9 Michael Hanselmann
    inst = objects.Instance.FromDict(inst_s)
321 a8083063 Iustin Pop
    return backend.AddOSToInstance(inst, os_disk, swap_disk)
322 a8083063 Iustin Pop
323 3ecf6786 Iustin Pop
  @staticmethod
324 decd5f45 Iustin Pop
  def perspective_instance_run_rename(params):
325 decd5f45 Iustin Pop
    """Runs the OS rename script for an instance.
326 decd5f45 Iustin Pop
327 decd5f45 Iustin Pop
    """
328 decd5f45 Iustin Pop
    inst_s, old_name, os_disk, swap_disk = params
329 319856a9 Michael Hanselmann
    inst = objects.Instance.FromDict(inst_s)
330 decd5f45 Iustin Pop
    return backend.RunRenameInstance(inst, old_name, os_disk, swap_disk)
331 decd5f45 Iustin Pop
332 decd5f45 Iustin Pop
  @staticmethod
333 3ecf6786 Iustin Pop
  def perspective_instance_os_import(params):
334 3ecf6786 Iustin Pop
    """Run the import function of an OS onto a given instance.
335 3ecf6786 Iustin Pop
336 3ecf6786 Iustin Pop
    """
337 62c9ec92 Iustin Pop
    inst_s, os_disk, swap_disk, src_node, src_image, cluster_name = params
338 319856a9 Michael Hanselmann
    inst = objects.Instance.FromDict(inst_s)
339 a8083063 Iustin Pop
    return backend.ImportOSIntoInstance(inst, os_disk, swap_disk,
340 62c9ec92 Iustin Pop
                                        src_node, src_image, cluster_name)
341 a8083063 Iustin Pop
342 3ecf6786 Iustin Pop
  @staticmethod
343 3ecf6786 Iustin Pop
  def perspective_instance_shutdown(params):
344 3ecf6786 Iustin Pop
    """Shutdown an instance.
345 3ecf6786 Iustin Pop
346 3ecf6786 Iustin Pop
    """
347 319856a9 Michael Hanselmann
    instance = objects.Instance.FromDict(params[0])
348 a8083063 Iustin Pop
    return backend.ShutdownInstance(instance)
349 a8083063 Iustin Pop
350 3ecf6786 Iustin Pop
  @staticmethod
351 3ecf6786 Iustin Pop
  def perspective_instance_start(params):
352 3ecf6786 Iustin Pop
    """Start an instance.
353 3ecf6786 Iustin Pop
354 3ecf6786 Iustin Pop
    """
355 319856a9 Michael Hanselmann
    instance = objects.Instance.FromDict(params[0])
356 a8083063 Iustin Pop
    extra_args = params[1]
357 a8083063 Iustin Pop
    return backend.StartInstance(instance, extra_args)
358 a8083063 Iustin Pop
359 3ecf6786 Iustin Pop
  @staticmethod
360 2a10865c Iustin Pop
  def perspective_instance_migrate(params):
361 2a10865c Iustin Pop
    """Migrates an instance.
362 2a10865c Iustin Pop
363 2a10865c Iustin Pop
    """
364 2a10865c Iustin Pop
    instance, target, live = params
365 2a10865c Iustin Pop
    return backend.MigrateInstance(instance, target, live)
366 2a10865c Iustin Pop
367 2a10865c Iustin Pop
  @staticmethod
368 007a2f3e Alexander Schreiber
  def perspective_instance_reboot(params):
369 007a2f3e Alexander Schreiber
    """Reboot an instance.
370 007a2f3e Alexander Schreiber
371 007a2f3e Alexander Schreiber
    """
372 007a2f3e Alexander Schreiber
    instance = objects.Instance.FromDict(params[0])
373 007a2f3e Alexander Schreiber
    reboot_type = params[1]
374 007a2f3e Alexander Schreiber
    extra_args = params[2]
375 007a2f3e Alexander Schreiber
    return backend.RebootInstance(instance, reboot_type, extra_args)
376 007a2f3e Alexander Schreiber
377 007a2f3e Alexander Schreiber
  @staticmethod
378 3ecf6786 Iustin Pop
  def perspective_instance_info(params):
379 3ecf6786 Iustin Pop
    """Query instance information.
380 3ecf6786 Iustin Pop
381 3ecf6786 Iustin Pop
    """
382 a8083063 Iustin Pop
    return backend.GetInstanceInfo(params[0])
383 a8083063 Iustin Pop
384 3ecf6786 Iustin Pop
  @staticmethod
385 3ecf6786 Iustin Pop
  def perspective_all_instances_info(params):
386 3ecf6786 Iustin Pop
    """Query information about all instances.
387 3ecf6786 Iustin Pop
388 3ecf6786 Iustin Pop
    """
389 a8083063 Iustin Pop
    return backend.GetAllInstancesInfo()
390 a8083063 Iustin Pop
391 3ecf6786 Iustin Pop
  @staticmethod
392 3ecf6786 Iustin Pop
  def perspective_instance_list(params):
393 3ecf6786 Iustin Pop
    """Query the list of running instances.
394 3ecf6786 Iustin Pop
395 3ecf6786 Iustin Pop
    """
396 a8083063 Iustin Pop
    return backend.GetInstanceList()
397 a8083063 Iustin Pop
398 a8083063 Iustin Pop
  # node --------------------------
399 a8083063 Iustin Pop
400 3ecf6786 Iustin Pop
  @staticmethod
401 16abfbc2 Alexander Schreiber
  def perspective_node_tcp_ping(params):
402 16abfbc2 Alexander Schreiber
    """Do a TcpPing on the remote node.
403 16abfbc2 Alexander Schreiber
404 16abfbc2 Alexander Schreiber
    """
405 b15d625f Iustin Pop
    return utils.TcpPing(params[1], params[2], timeout=params[3],
406 b15d625f Iustin Pop
                         live_port_needed=params[4], source=params[0])
407 16abfbc2 Alexander Schreiber
408 16abfbc2 Alexander Schreiber
  @staticmethod
409 3ecf6786 Iustin Pop
  def perspective_node_info(params):
410 3ecf6786 Iustin Pop
    """Query node information.
411 3ecf6786 Iustin Pop
412 3ecf6786 Iustin Pop
    """
413 a8083063 Iustin Pop
    vgname = params[0]
414 a8083063 Iustin Pop
    return backend.GetNodeInfo(vgname)
415 a8083063 Iustin Pop
416 3ecf6786 Iustin Pop
  @staticmethod
417 3ecf6786 Iustin Pop
  def perspective_node_add(params):
418 3ecf6786 Iustin Pop
    """Complete the registration of this node in the cluster.
419 3ecf6786 Iustin Pop
420 3ecf6786 Iustin Pop
    """
421 a8083063 Iustin Pop
    return backend.AddNode(params[0], params[1], params[2],
422 a8083063 Iustin Pop
                           params[3], params[4], params[5])
423 a8083063 Iustin Pop
424 3ecf6786 Iustin Pop
  @staticmethod
425 3ecf6786 Iustin Pop
  def perspective_node_verify(params):
426 3ecf6786 Iustin Pop
    """Run a verify sequence on this node.
427 3ecf6786 Iustin Pop
428 3ecf6786 Iustin Pop
    """
429 62c9ec92 Iustin Pop
    return backend.VerifyNode(params[0], params[1])
430 a8083063 Iustin Pop
431 3ecf6786 Iustin Pop
  @staticmethod
432 3ecf6786 Iustin Pop
  def perspective_node_start_master(params):
433 3ecf6786 Iustin Pop
    """Promote this node to master status.
434 3ecf6786 Iustin Pop
435 3ecf6786 Iustin Pop
    """
436 1c65840b Iustin Pop
    return backend.StartMaster(params[0])
437 a8083063 Iustin Pop
438 3ecf6786 Iustin Pop
  @staticmethod
439 3ecf6786 Iustin Pop
  def perspective_node_stop_master(params):
440 3ecf6786 Iustin Pop
    """Demote this node from master status.
441 3ecf6786 Iustin Pop
442 3ecf6786 Iustin Pop
    """
443 1c65840b Iustin Pop
    return backend.StopMaster(params[0])
444 a8083063 Iustin Pop
445 3ecf6786 Iustin Pop
  @staticmethod
446 3ecf6786 Iustin Pop
  def perspective_node_leave_cluster(params):
447 3ecf6786 Iustin Pop
    """Cleanup after leaving a cluster.
448 3ecf6786 Iustin Pop
449 3ecf6786 Iustin Pop
    """
450 a8083063 Iustin Pop
    return backend.LeaveCluster()
451 a8083063 Iustin Pop
452 3ecf6786 Iustin Pop
  @staticmethod
453 3ecf6786 Iustin Pop
  def perspective_node_volumes(params):
454 3ecf6786 Iustin Pop
    """Query the list of all logical volume groups.
455 3ecf6786 Iustin Pop
456 3ecf6786 Iustin Pop
    """
457 dcb93971 Michael Hanselmann
    return backend.NodeVolumes()
458 dcb93971 Michael Hanselmann
459 a8083063 Iustin Pop
  # cluster --------------------------
460 a8083063 Iustin Pop
461 3ecf6786 Iustin Pop
  @staticmethod
462 3ecf6786 Iustin Pop
  def perspective_version(params):
463 3ecf6786 Iustin Pop
    """Query version information.
464 3ecf6786 Iustin Pop
465 3ecf6786 Iustin Pop
    """
466 a8083063 Iustin Pop
    return constants.PROTOCOL_VERSION
467 a8083063 Iustin Pop
468 3ecf6786 Iustin Pop
  @staticmethod
469 3ecf6786 Iustin Pop
  def perspective_upload_file(params):
470 3ecf6786 Iustin Pop
    """Upload a file.
471 3ecf6786 Iustin Pop
472 3ecf6786 Iustin Pop
    Note that the backend implementation imposes strict rules on which
473 3ecf6786 Iustin Pop
    files are accepted.
474 3ecf6786 Iustin Pop
475 3ecf6786 Iustin Pop
    """
476 a8083063 Iustin Pop
    return backend.UploadFile(*params)
477 a8083063 Iustin Pop
478 4e071d3b Iustin Pop
  @staticmethod
479 4e071d3b Iustin Pop
  def perspective_master_info(params):
480 4e071d3b Iustin Pop
    """Query master information.
481 4e071d3b Iustin Pop
482 4e071d3b Iustin Pop
    """
483 4e071d3b Iustin Pop
    return backend.GetMasterInfo()
484 a8083063 Iustin Pop
485 a8083063 Iustin Pop
  # os -----------------------
486 a8083063 Iustin Pop
487 3ecf6786 Iustin Pop
  @staticmethod
488 3ecf6786 Iustin Pop
  def perspective_os_diagnose(params):
489 3ecf6786 Iustin Pop
    """Query detailed information about existing OSes.
490 3ecf6786 Iustin Pop
491 3ecf6786 Iustin Pop
    """
492 4e679f11 Guido Trotter
    return [os.ToDict() for os in backend.DiagnoseOS()]
493 a8083063 Iustin Pop
494 3ecf6786 Iustin Pop
  @staticmethod
495 3ecf6786 Iustin Pop
  def perspective_os_get(params):
496 3ecf6786 Iustin Pop
    """Query information about a given OS.
497 3ecf6786 Iustin Pop
498 3ecf6786 Iustin Pop
    """
499 a8083063 Iustin Pop
    name = params[0]
500 a8083063 Iustin Pop
    try:
501 dfa96ded Guido Trotter
      os_obj = backend.OSFromDisk(name)
502 a8083063 Iustin Pop
    except errors.InvalidOS, err:
503 dfa96ded Guido Trotter
      os_obj = objects.OS.FromInvalidOS(err)
504 dfa96ded Guido Trotter
    return os_obj.ToDict()
505 a8083063 Iustin Pop
506 a8083063 Iustin Pop
  # hooks -----------------------
507 a8083063 Iustin Pop
508 3ecf6786 Iustin Pop
  @staticmethod
509 3ecf6786 Iustin Pop
  def perspective_hooks_runner(params):
510 3ecf6786 Iustin Pop
    """Run hook scripts.
511 3ecf6786 Iustin Pop
512 3ecf6786 Iustin Pop
    """
513 a8083063 Iustin Pop
    hpath, phase, env = params
514 a8083063 Iustin Pop
    hr = backend.HooksRunner()
515 a8083063 Iustin Pop
    return hr.RunHooks(hpath, phase, env)
516 a8083063 Iustin Pop
517 8d528b7c Iustin Pop
  # iallocator -----------------
518 8d528b7c Iustin Pop
519 8d528b7c Iustin Pop
  @staticmethod
520 8d528b7c Iustin Pop
  def perspective_iallocator_runner(params):
521 8d528b7c Iustin Pop
    """Run an iallocator script.
522 8d528b7c Iustin Pop
523 8d528b7c Iustin Pop
    """
524 8d528b7c Iustin Pop
    name, idata = params
525 8d528b7c Iustin Pop
    iar = backend.IAllocatorRunner()
526 8d528b7c Iustin Pop
    return iar.Run(name, idata)
527 8d528b7c Iustin Pop
528 06009e27 Iustin Pop
  # test -----------------------
529 06009e27 Iustin Pop
530 06009e27 Iustin Pop
  @staticmethod
531 06009e27 Iustin Pop
  def perspective_test_delay(params):
532 06009e27 Iustin Pop
    """Run test delay.
533 06009e27 Iustin Pop
534 06009e27 Iustin Pop
    """
535 06009e27 Iustin Pop
    duration = params[0]
536 06009e27 Iustin Pop
    return utils.TestDelay(duration)
537 06009e27 Iustin Pop
538 4e071d3b Iustin Pop
  # file storage ---------------
539 4e071d3b Iustin Pop
540 a5d7fb43 Manuel Franceschini
  @staticmethod
541 a5d7fb43 Manuel Franceschini
  def perspective_file_storage_dir_create(params):
542 a5d7fb43 Manuel Franceschini
    """Create the file storage directory.
543 a5d7fb43 Manuel Franceschini
544 a5d7fb43 Manuel Franceschini
    """
545 a5d7fb43 Manuel Franceschini
    file_storage_dir = params[0]
546 a5d7fb43 Manuel Franceschini
    return backend.CreateFileStorageDir(file_storage_dir)
547 a5d7fb43 Manuel Franceschini
548 a5d7fb43 Manuel Franceschini
  @staticmethod
549 a5d7fb43 Manuel Franceschini
  def perspective_file_storage_dir_remove(params):
550 a5d7fb43 Manuel Franceschini
    """Remove the file storage directory.
551 a5d7fb43 Manuel Franceschini
552 a5d7fb43 Manuel Franceschini
    """
553 a5d7fb43 Manuel Franceschini
    file_storage_dir = params[0]
554 a5d7fb43 Manuel Franceschini
    return backend.RemoveFileStorageDir(file_storage_dir)
555 a5d7fb43 Manuel Franceschini
556 a5d7fb43 Manuel Franceschini
  @staticmethod
557 a5d7fb43 Manuel Franceschini
  def perspective_file_storage_dir_rename(params):
558 a5d7fb43 Manuel Franceschini
    """Rename the file storage directory.
559 a5d7fb43 Manuel Franceschini
560 a5d7fb43 Manuel Franceschini
    """
561 a5d7fb43 Manuel Franceschini
    old_file_storage_dir = params[0]
562 a5d7fb43 Manuel Franceschini
    new_file_storage_dir = params[1]
563 a5d7fb43 Manuel Franceschini
    return backend.RenameFileStorageDir(old_file_storage_dir,
564 a5d7fb43 Manuel Franceschini
                                        new_file_storage_dir)
565 a5d7fb43 Manuel Franceschini
566 4e071d3b Iustin Pop
  # jobs ------------------------
567 4e071d3b Iustin Pop
568 ca52cdeb Michael Hanselmann
  @staticmethod
569 7f30777b Michael Hanselmann
  @_RequireJobQueueLock
570 ca52cdeb Michael Hanselmann
  def perspective_jobqueue_update(params):
571 ca52cdeb Michael Hanselmann
    """Update job queue.
572 ca52cdeb Michael Hanselmann
573 ca52cdeb Michael Hanselmann
    """
574 ca52cdeb Michael Hanselmann
    (file_name, content) = params
575 7f30777b Michael Hanselmann
    return backend.JobQueueUpdate(file_name, content)
576 ca52cdeb Michael Hanselmann
577 ca52cdeb Michael Hanselmann
  @staticmethod
578 f1f3f45c Michael Hanselmann
  @_RequireJobQueueLock
579 ca52cdeb Michael Hanselmann
  def perspective_jobqueue_purge(params):
580 ca52cdeb Michael Hanselmann
    """Purge job queue.
581 ca52cdeb Michael Hanselmann
582 ca52cdeb Michael Hanselmann
    """
583 ca52cdeb Michael Hanselmann
    return backend.JobQueuePurge()
584 ca52cdeb Michael Hanselmann
585 af5ebcb1 Michael Hanselmann
  @staticmethod
586 af5ebcb1 Michael Hanselmann
  @_RequireJobQueueLock
587 af5ebcb1 Michael Hanselmann
  def perspective_jobqueue_rename(params):
588 af5ebcb1 Michael Hanselmann
    """Rename a job queue file.
589 af5ebcb1 Michael Hanselmann
590 af5ebcb1 Michael Hanselmann
    """
591 af5ebcb1 Michael Hanselmann
    (old, new) = params
592 af5ebcb1 Michael Hanselmann
593 af5ebcb1 Michael Hanselmann
    return backend.JobQueueRename(old, new)
594 af5ebcb1 Michael Hanselmann
595 a8083063 Iustin Pop
596 1df6506c Michael Hanselmann
class NodeDaemonHttpServer(http.HTTPServer):
597 1df6506c Michael Hanselmann
  def __init__(self, server_address):
598 1df6506c Michael Hanselmann
    http.HTTPServer.__init__(self, server_address, NodeDaemonRequestHandler)
599 84b58db2 Michael Hanselmann
    self.noded_pid = os.getpid()
600 84b58db2 Michael Hanselmann
601 84b58db2 Michael Hanselmann
  def serve_forever(self):
602 84b58db2 Michael Hanselmann
    """Handle requests until told to quit."""
603 84b58db2 Michael Hanselmann
    sighandler = utils.SignalHandler([signal.SIGINT, signal.SIGTERM])
604 84b58db2 Michael Hanselmann
    try:
605 84b58db2 Michael Hanselmann
      while not sighandler.called:
606 84b58db2 Michael Hanselmann
        self.handle_request()
607 84b58db2 Michael Hanselmann
      # TODO: There could be children running at this point
608 84b58db2 Michael Hanselmann
    finally:
609 84b58db2 Michael Hanselmann
      sighandler.Reset()
610 1df6506c Michael Hanselmann
611 1df6506c Michael Hanselmann
612 761ce945 Guido Trotter
class ForkingHTTPServer(SocketServer.ForkingMixIn, NodeDaemonHttpServer):
613 761ce945 Guido Trotter
  """Forking HTTP Server.
614 761ce945 Guido Trotter
615 761ce945 Guido Trotter
  This inherits from ForkingMixIn and HTTPServer in order to fork for each
616 761ce945 Guido Trotter
  request we handle. This allows more requests to be handled concurrently.
617 761ce945 Guido Trotter
618 761ce945 Guido Trotter
  """
619 761ce945 Guido Trotter
620 761ce945 Guido Trotter
621 a8083063 Iustin Pop
def ParseOptions():
622 a8083063 Iustin Pop
  """Parse the command line options.
623 a8083063 Iustin Pop
624 a8083063 Iustin Pop
  Returns:
625 a8083063 Iustin Pop
    (options, args) as from OptionParser.parse_args()
626 a8083063 Iustin Pop
627 a8083063 Iustin Pop
  """
628 a8083063 Iustin Pop
  parser = OptionParser(description="Ganeti node daemon",
629 a8083063 Iustin Pop
                        usage="%prog [-f] [-d]",
630 a8083063 Iustin Pop
                        version="%%prog (ganeti) %s" %
631 a8083063 Iustin Pop
                        constants.RELEASE_VERSION)
632 a8083063 Iustin Pop
633 a8083063 Iustin Pop
  parser.add_option("-f", "--foreground", dest="fork",
634 a8083063 Iustin Pop
                    help="Don't detach from the current terminal",
635 a8083063 Iustin Pop
                    default=True, action="store_false")
636 a8083063 Iustin Pop
  parser.add_option("-d", "--debug", dest="debug",
637 a8083063 Iustin Pop
                    help="Enable some debug messages",
638 a8083063 Iustin Pop
                    default=False, action="store_true")
639 a8083063 Iustin Pop
  options, args = parser.parse_args()
640 a8083063 Iustin Pop
  return options, args
641 a8083063 Iustin Pop
642 a8083063 Iustin Pop
643 a8083063 Iustin Pop
def main():
644 3ecf6786 Iustin Pop
  """Main function for the node daemon.
645 3ecf6786 Iustin Pop
646 3ecf6786 Iustin Pop
  """
647 25d6d12a Michael Hanselmann
  global queue_lock
648 25d6d12a Michael Hanselmann
649 a8083063 Iustin Pop
  options, args = ParseOptions()
650 f362096f Iustin Pop
  utils.debug = options.debug
651 a8083063 Iustin Pop
  for fname in (constants.SSL_CERT_FILE,):
652 a8083063 Iustin Pop
    if not os.path.isfile(fname):
653 a8083063 Iustin Pop
      print "config %s not there, will not run." % fname
654 a8083063 Iustin Pop
      sys.exit(5)
655 a8083063 Iustin Pop
656 a8083063 Iustin Pop
  try:
657 8594f271 Michael Hanselmann
    port = utils.GetNodeDaemonPort()
658 8594f271 Michael Hanselmann
    pwdata = utils.GetNodeDaemonPassword()
659 a8083063 Iustin Pop
  except errors.ConfigurationError, err:
660 a8083063 Iustin Pop
    print "Cluster configuration incomplete: '%s'" % str(err)
661 a8083063 Iustin Pop
    sys.exit(5)
662 a8083063 Iustin Pop
663 195c7f91 Iustin Pop
  # create the various SUB_RUN_DIRS, if not existing, so that we handle the
664 195c7f91 Iustin Pop
  # situation where RUN_DIR is tmpfs
665 195c7f91 Iustin Pop
  for dir_name in constants.SUB_RUN_DIRS:
666 195c7f91 Iustin Pop
    if not os.path.exists(dir_name):
667 195c7f91 Iustin Pop
      try:
668 195c7f91 Iustin Pop
        os.mkdir(dir_name, 0755)
669 195c7f91 Iustin Pop
      except EnvironmentError, err:
670 195c7f91 Iustin Pop
        if err.errno != errno.EEXIST:
671 195c7f91 Iustin Pop
          print ("Node setup wrong, cannot create directory %s: %s" %
672 195c7f91 Iustin Pop
                 (dir_name, err))
673 195c7f91 Iustin Pop
          sys.exit(5)
674 195c7f91 Iustin Pop
    if not os.path.isdir(dir_name):
675 195c7f91 Iustin Pop
      print ("Node setup wrong, %s is not a directory" % dir_name)
676 195c7f91 Iustin Pop
      sys.exit(5)
677 0214b0c0 Iustin Pop
678 a8083063 Iustin Pop
  # become a daemon
679 a8083063 Iustin Pop
  if options.fork:
680 8f765069 Iustin Pop
    utils.Daemonize(logfile=constants.LOG_NODESERVER)
681 a8083063 Iustin Pop
682 99e88451 Iustin Pop
  utils.WritePidFile(constants.NODED_PID)
683 73d927a2 Guido Trotter
684 59f187eb Iustin Pop
  logger.SetupLogging(logfile=constants.LOG_NODESERVER, debug=options.debug,
685 59f187eb Iustin Pop
                      stderr_logging=not options.fork)
686 c89189b1 Iustin Pop
  logging.info("ganeti node daemon startup")
687 a8083063 Iustin Pop
688 25d6d12a Michael Hanselmann
  # Prepare job queue
689 25d6d12a Michael Hanselmann
  queue_lock = jstore.InitAndVerifyQueue(must_lock=False)
690 25d6d12a Michael Hanselmann
691 761ce945 Guido Trotter
  if options.fork:
692 84b58db2 Michael Hanselmann
    server = ForkingHTTPServer(('', port))
693 761ce945 Guido Trotter
  else:
694 84b58db2 Michael Hanselmann
    server = NodeDaemonHttpServer(('', port))
695 a8083063 Iustin Pop
696 73d927a2 Guido Trotter
  try:
697 73d927a2 Guido Trotter
    server.serve_forever()
698 73d927a2 Guido Trotter
  finally:
699 99e88451 Iustin Pop
    utils.RemovePidFile(constants.NODED_PID)
700 73d927a2 Guido Trotter
701 a8083063 Iustin Pop
702 3ecf6786 Iustin Pop
if __name__ == '__main__':
703 a8083063 Iustin Pop
  main()