Statistics
| Branch: | Tag: | Revision:

root / daemons / ganeti-noded @ e69d05fd

History | View | Annotate | Download (18.1 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 9f0e6b37 Iustin Pop
    instance = objects.Instance.FromDict(instance)
366 2a10865c Iustin Pop
    return backend.MigrateInstance(instance, target, live)
367 2a10865c Iustin Pop
368 2a10865c Iustin Pop
  @staticmethod
369 007a2f3e Alexander Schreiber
  def perspective_instance_reboot(params):
370 007a2f3e Alexander Schreiber
    """Reboot an instance.
371 007a2f3e Alexander Schreiber
372 007a2f3e Alexander Schreiber
    """
373 007a2f3e Alexander Schreiber
    instance = objects.Instance.FromDict(params[0])
374 007a2f3e Alexander Schreiber
    reboot_type = params[1]
375 007a2f3e Alexander Schreiber
    extra_args = params[2]
376 007a2f3e Alexander Schreiber
    return backend.RebootInstance(instance, reboot_type, extra_args)
377 007a2f3e Alexander Schreiber
378 007a2f3e Alexander Schreiber
  @staticmethod
379 3ecf6786 Iustin Pop
  def perspective_instance_info(params):
380 3ecf6786 Iustin Pop
    """Query instance information.
381 3ecf6786 Iustin Pop
382 3ecf6786 Iustin Pop
    """
383 a8083063 Iustin Pop
    return backend.GetInstanceInfo(params[0])
384 a8083063 Iustin Pop
385 3ecf6786 Iustin Pop
  @staticmethod
386 3ecf6786 Iustin Pop
  def perspective_all_instances_info(params):
387 3ecf6786 Iustin Pop
    """Query information about all instances.
388 3ecf6786 Iustin Pop
389 3ecf6786 Iustin Pop
    """
390 e69d05fd Iustin Pop
    return backend.GetAllInstancesInfo(params[0])
391 a8083063 Iustin Pop
392 3ecf6786 Iustin Pop
  @staticmethod
393 3ecf6786 Iustin Pop
  def perspective_instance_list(params):
394 3ecf6786 Iustin Pop
    """Query the list of running instances.
395 3ecf6786 Iustin Pop
396 3ecf6786 Iustin Pop
    """
397 e69d05fd Iustin Pop
    return backend.GetInstanceList(params[0])
398 a8083063 Iustin Pop
399 a8083063 Iustin Pop
  # node --------------------------
400 a8083063 Iustin Pop
401 3ecf6786 Iustin Pop
  @staticmethod
402 16abfbc2 Alexander Schreiber
  def perspective_node_tcp_ping(params):
403 16abfbc2 Alexander Schreiber
    """Do a TcpPing on the remote node.
404 16abfbc2 Alexander Schreiber
405 16abfbc2 Alexander Schreiber
    """
406 b15d625f Iustin Pop
    return utils.TcpPing(params[1], params[2], timeout=params[3],
407 b15d625f Iustin Pop
                         live_port_needed=params[4], source=params[0])
408 16abfbc2 Alexander Schreiber
409 16abfbc2 Alexander Schreiber
  @staticmethod
410 3ecf6786 Iustin Pop
  def perspective_node_info(params):
411 3ecf6786 Iustin Pop
    """Query node information.
412 3ecf6786 Iustin Pop
413 3ecf6786 Iustin Pop
    """
414 e69d05fd Iustin Pop
    vgname, hypervisor_type = params
415 e69d05fd Iustin Pop
    return backend.GetNodeInfo(vgname, hypervisor_type)
416 a8083063 Iustin Pop
417 3ecf6786 Iustin Pop
  @staticmethod
418 3ecf6786 Iustin Pop
  def perspective_node_add(params):
419 3ecf6786 Iustin Pop
    """Complete the registration of this node in the cluster.
420 3ecf6786 Iustin Pop
421 3ecf6786 Iustin Pop
    """
422 a8083063 Iustin Pop
    return backend.AddNode(params[0], params[1], params[2],
423 a8083063 Iustin Pop
                           params[3], params[4], params[5])
424 a8083063 Iustin Pop
425 3ecf6786 Iustin Pop
  @staticmethod
426 3ecf6786 Iustin Pop
  def perspective_node_verify(params):
427 3ecf6786 Iustin Pop
    """Run a verify sequence on this node.
428 3ecf6786 Iustin Pop
429 3ecf6786 Iustin Pop
    """
430 62c9ec92 Iustin Pop
    return backend.VerifyNode(params[0], params[1])
431 a8083063 Iustin Pop
432 3ecf6786 Iustin Pop
  @staticmethod
433 3ecf6786 Iustin Pop
  def perspective_node_start_master(params):
434 3ecf6786 Iustin Pop
    """Promote this node to master status.
435 3ecf6786 Iustin Pop
436 3ecf6786 Iustin Pop
    """
437 1c65840b Iustin Pop
    return backend.StartMaster(params[0])
438 a8083063 Iustin Pop
439 3ecf6786 Iustin Pop
  @staticmethod
440 3ecf6786 Iustin Pop
  def perspective_node_stop_master(params):
441 3ecf6786 Iustin Pop
    """Demote this node from master status.
442 3ecf6786 Iustin Pop
443 3ecf6786 Iustin Pop
    """
444 1c65840b Iustin Pop
    return backend.StopMaster(params[0])
445 a8083063 Iustin Pop
446 3ecf6786 Iustin Pop
  @staticmethod
447 3ecf6786 Iustin Pop
  def perspective_node_leave_cluster(params):
448 3ecf6786 Iustin Pop
    """Cleanup after leaving a cluster.
449 3ecf6786 Iustin Pop
450 3ecf6786 Iustin Pop
    """
451 a8083063 Iustin Pop
    return backend.LeaveCluster()
452 a8083063 Iustin Pop
453 3ecf6786 Iustin Pop
  @staticmethod
454 3ecf6786 Iustin Pop
  def perspective_node_volumes(params):
455 3ecf6786 Iustin Pop
    """Query the list of all logical volume groups.
456 3ecf6786 Iustin Pop
457 3ecf6786 Iustin Pop
    """
458 dcb93971 Michael Hanselmann
    return backend.NodeVolumes()
459 dcb93971 Michael Hanselmann
460 a8083063 Iustin Pop
  # cluster --------------------------
461 a8083063 Iustin Pop
462 3ecf6786 Iustin Pop
  @staticmethod
463 3ecf6786 Iustin Pop
  def perspective_version(params):
464 3ecf6786 Iustin Pop
    """Query version information.
465 3ecf6786 Iustin Pop
466 3ecf6786 Iustin Pop
    """
467 a8083063 Iustin Pop
    return constants.PROTOCOL_VERSION
468 a8083063 Iustin Pop
469 3ecf6786 Iustin Pop
  @staticmethod
470 3ecf6786 Iustin Pop
  def perspective_upload_file(params):
471 3ecf6786 Iustin Pop
    """Upload a file.
472 3ecf6786 Iustin Pop
473 3ecf6786 Iustin Pop
    Note that the backend implementation imposes strict rules on which
474 3ecf6786 Iustin Pop
    files are accepted.
475 3ecf6786 Iustin Pop
476 3ecf6786 Iustin Pop
    """
477 a8083063 Iustin Pop
    return backend.UploadFile(*params)
478 a8083063 Iustin Pop
479 4e071d3b Iustin Pop
  @staticmethod
480 4e071d3b Iustin Pop
  def perspective_master_info(params):
481 4e071d3b Iustin Pop
    """Query master information.
482 4e071d3b Iustin Pop
483 4e071d3b Iustin Pop
    """
484 4e071d3b Iustin Pop
    return backend.GetMasterInfo()
485 a8083063 Iustin Pop
486 a8083063 Iustin Pop
  # os -----------------------
487 a8083063 Iustin Pop
488 3ecf6786 Iustin Pop
  @staticmethod
489 3ecf6786 Iustin Pop
  def perspective_os_diagnose(params):
490 3ecf6786 Iustin Pop
    """Query detailed information about existing OSes.
491 3ecf6786 Iustin Pop
492 3ecf6786 Iustin Pop
    """
493 4e679f11 Guido Trotter
    return [os.ToDict() for os in backend.DiagnoseOS()]
494 a8083063 Iustin Pop
495 3ecf6786 Iustin Pop
  @staticmethod
496 3ecf6786 Iustin Pop
  def perspective_os_get(params):
497 3ecf6786 Iustin Pop
    """Query information about a given OS.
498 3ecf6786 Iustin Pop
499 3ecf6786 Iustin Pop
    """
500 a8083063 Iustin Pop
    name = params[0]
501 a8083063 Iustin Pop
    try:
502 dfa96ded Guido Trotter
      os_obj = backend.OSFromDisk(name)
503 a8083063 Iustin Pop
    except errors.InvalidOS, err:
504 dfa96ded Guido Trotter
      os_obj = objects.OS.FromInvalidOS(err)
505 dfa96ded Guido Trotter
    return os_obj.ToDict()
506 a8083063 Iustin Pop
507 a8083063 Iustin Pop
  # hooks -----------------------
508 a8083063 Iustin Pop
509 3ecf6786 Iustin Pop
  @staticmethod
510 3ecf6786 Iustin Pop
  def perspective_hooks_runner(params):
511 3ecf6786 Iustin Pop
    """Run hook scripts.
512 3ecf6786 Iustin Pop
513 3ecf6786 Iustin Pop
    """
514 a8083063 Iustin Pop
    hpath, phase, env = params
515 a8083063 Iustin Pop
    hr = backend.HooksRunner()
516 a8083063 Iustin Pop
    return hr.RunHooks(hpath, phase, env)
517 a8083063 Iustin Pop
518 8d528b7c Iustin Pop
  # iallocator -----------------
519 8d528b7c Iustin Pop
520 8d528b7c Iustin Pop
  @staticmethod
521 8d528b7c Iustin Pop
  def perspective_iallocator_runner(params):
522 8d528b7c Iustin Pop
    """Run an iallocator script.
523 8d528b7c Iustin Pop
524 8d528b7c Iustin Pop
    """
525 8d528b7c Iustin Pop
    name, idata = params
526 8d528b7c Iustin Pop
    iar = backend.IAllocatorRunner()
527 8d528b7c Iustin Pop
    return iar.Run(name, idata)
528 8d528b7c Iustin Pop
529 06009e27 Iustin Pop
  # test -----------------------
530 06009e27 Iustin Pop
531 06009e27 Iustin Pop
  @staticmethod
532 06009e27 Iustin Pop
  def perspective_test_delay(params):
533 06009e27 Iustin Pop
    """Run test delay.
534 06009e27 Iustin Pop
535 06009e27 Iustin Pop
    """
536 06009e27 Iustin Pop
    duration = params[0]
537 06009e27 Iustin Pop
    return utils.TestDelay(duration)
538 06009e27 Iustin Pop
539 4e071d3b Iustin Pop
  # file storage ---------------
540 4e071d3b Iustin Pop
541 a5d7fb43 Manuel Franceschini
  @staticmethod
542 a5d7fb43 Manuel Franceschini
  def perspective_file_storage_dir_create(params):
543 a5d7fb43 Manuel Franceschini
    """Create the file storage directory.
544 a5d7fb43 Manuel Franceschini
545 a5d7fb43 Manuel Franceschini
    """
546 a5d7fb43 Manuel Franceschini
    file_storage_dir = params[0]
547 a5d7fb43 Manuel Franceschini
    return backend.CreateFileStorageDir(file_storage_dir)
548 a5d7fb43 Manuel Franceschini
549 a5d7fb43 Manuel Franceschini
  @staticmethod
550 a5d7fb43 Manuel Franceschini
  def perspective_file_storage_dir_remove(params):
551 a5d7fb43 Manuel Franceschini
    """Remove 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.RemoveFileStorageDir(file_storage_dir)
556 a5d7fb43 Manuel Franceschini
557 a5d7fb43 Manuel Franceschini
  @staticmethod
558 a5d7fb43 Manuel Franceschini
  def perspective_file_storage_dir_rename(params):
559 a5d7fb43 Manuel Franceschini
    """Rename the file storage directory.
560 a5d7fb43 Manuel Franceschini
561 a5d7fb43 Manuel Franceschini
    """
562 a5d7fb43 Manuel Franceschini
    old_file_storage_dir = params[0]
563 a5d7fb43 Manuel Franceschini
    new_file_storage_dir = params[1]
564 a5d7fb43 Manuel Franceschini
    return backend.RenameFileStorageDir(old_file_storage_dir,
565 a5d7fb43 Manuel Franceschini
                                        new_file_storage_dir)
566 a5d7fb43 Manuel Franceschini
567 4e071d3b Iustin Pop
  # jobs ------------------------
568 4e071d3b Iustin Pop
569 ca52cdeb Michael Hanselmann
  @staticmethod
570 7f30777b Michael Hanselmann
  @_RequireJobQueueLock
571 ca52cdeb Michael Hanselmann
  def perspective_jobqueue_update(params):
572 ca52cdeb Michael Hanselmann
    """Update job queue.
573 ca52cdeb Michael Hanselmann
574 ca52cdeb Michael Hanselmann
    """
575 ca52cdeb Michael Hanselmann
    (file_name, content) = params
576 7f30777b Michael Hanselmann
    return backend.JobQueueUpdate(file_name, content)
577 ca52cdeb Michael Hanselmann
578 ca52cdeb Michael Hanselmann
  @staticmethod
579 f1f3f45c Michael Hanselmann
  @_RequireJobQueueLock
580 ca52cdeb Michael Hanselmann
  def perspective_jobqueue_purge(params):
581 ca52cdeb Michael Hanselmann
    """Purge job queue.
582 ca52cdeb Michael Hanselmann
583 ca52cdeb Michael Hanselmann
    """
584 ca52cdeb Michael Hanselmann
    return backend.JobQueuePurge()
585 ca52cdeb Michael Hanselmann
586 af5ebcb1 Michael Hanselmann
  @staticmethod
587 af5ebcb1 Michael Hanselmann
  @_RequireJobQueueLock
588 af5ebcb1 Michael Hanselmann
  def perspective_jobqueue_rename(params):
589 af5ebcb1 Michael Hanselmann
    """Rename a job queue file.
590 af5ebcb1 Michael Hanselmann
591 af5ebcb1 Michael Hanselmann
    """
592 af5ebcb1 Michael Hanselmann
    (old, new) = params
593 af5ebcb1 Michael Hanselmann
594 af5ebcb1 Michael Hanselmann
    return backend.JobQueueRename(old, new)
595 af5ebcb1 Michael Hanselmann
596 a8083063 Iustin Pop
597 1df6506c Michael Hanselmann
class NodeDaemonHttpServer(http.HTTPServer):
598 1df6506c Michael Hanselmann
  def __init__(self, server_address):
599 1df6506c Michael Hanselmann
    http.HTTPServer.__init__(self, server_address, NodeDaemonRequestHandler)
600 84b58db2 Michael Hanselmann
    self.noded_pid = os.getpid()
601 84b58db2 Michael Hanselmann
602 84b58db2 Michael Hanselmann
  def serve_forever(self):
603 84b58db2 Michael Hanselmann
    """Handle requests until told to quit."""
604 84b58db2 Michael Hanselmann
    sighandler = utils.SignalHandler([signal.SIGINT, signal.SIGTERM])
605 84b58db2 Michael Hanselmann
    try:
606 84b58db2 Michael Hanselmann
      while not sighandler.called:
607 84b58db2 Michael Hanselmann
        self.handle_request()
608 84b58db2 Michael Hanselmann
      # TODO: There could be children running at this point
609 84b58db2 Michael Hanselmann
    finally:
610 84b58db2 Michael Hanselmann
      sighandler.Reset()
611 1df6506c Michael Hanselmann
612 1df6506c Michael Hanselmann
613 761ce945 Guido Trotter
class ForkingHTTPServer(SocketServer.ForkingMixIn, NodeDaemonHttpServer):
614 761ce945 Guido Trotter
  """Forking HTTP Server.
615 761ce945 Guido Trotter
616 761ce945 Guido Trotter
  This inherits from ForkingMixIn and HTTPServer in order to fork for each
617 761ce945 Guido Trotter
  request we handle. This allows more requests to be handled concurrently.
618 761ce945 Guido Trotter
619 761ce945 Guido Trotter
  """
620 761ce945 Guido Trotter
621 761ce945 Guido Trotter
622 a8083063 Iustin Pop
def ParseOptions():
623 a8083063 Iustin Pop
  """Parse the command line options.
624 a8083063 Iustin Pop
625 a8083063 Iustin Pop
  Returns:
626 a8083063 Iustin Pop
    (options, args) as from OptionParser.parse_args()
627 a8083063 Iustin Pop
628 a8083063 Iustin Pop
  """
629 a8083063 Iustin Pop
  parser = OptionParser(description="Ganeti node daemon",
630 a8083063 Iustin Pop
                        usage="%prog [-f] [-d]",
631 a8083063 Iustin Pop
                        version="%%prog (ganeti) %s" %
632 a8083063 Iustin Pop
                        constants.RELEASE_VERSION)
633 a8083063 Iustin Pop
634 a8083063 Iustin Pop
  parser.add_option("-f", "--foreground", dest="fork",
635 a8083063 Iustin Pop
                    help="Don't detach from the current terminal",
636 a8083063 Iustin Pop
                    default=True, action="store_false")
637 a8083063 Iustin Pop
  parser.add_option("-d", "--debug", dest="debug",
638 a8083063 Iustin Pop
                    help="Enable some debug messages",
639 a8083063 Iustin Pop
                    default=False, action="store_true")
640 a8083063 Iustin Pop
  options, args = parser.parse_args()
641 a8083063 Iustin Pop
  return options, args
642 a8083063 Iustin Pop
643 a8083063 Iustin Pop
644 a8083063 Iustin Pop
def main():
645 3ecf6786 Iustin Pop
  """Main function for the node daemon.
646 3ecf6786 Iustin Pop
647 3ecf6786 Iustin Pop
  """
648 25d6d12a Michael Hanselmann
  global queue_lock
649 25d6d12a Michael Hanselmann
650 a8083063 Iustin Pop
  options, args = ParseOptions()
651 f362096f Iustin Pop
  utils.debug = options.debug
652 a8083063 Iustin Pop
  for fname in (constants.SSL_CERT_FILE,):
653 a8083063 Iustin Pop
    if not os.path.isfile(fname):
654 a8083063 Iustin Pop
      print "config %s not there, will not run." % fname
655 a8083063 Iustin Pop
      sys.exit(5)
656 a8083063 Iustin Pop
657 a8083063 Iustin Pop
  try:
658 8594f271 Michael Hanselmann
    port = utils.GetNodeDaemonPort()
659 8594f271 Michael Hanselmann
    pwdata = utils.GetNodeDaemonPassword()
660 a8083063 Iustin Pop
  except errors.ConfigurationError, err:
661 a8083063 Iustin Pop
    print "Cluster configuration incomplete: '%s'" % str(err)
662 a8083063 Iustin Pop
    sys.exit(5)
663 a8083063 Iustin Pop
664 195c7f91 Iustin Pop
  # create the various SUB_RUN_DIRS, if not existing, so that we handle the
665 195c7f91 Iustin Pop
  # situation where RUN_DIR is tmpfs
666 195c7f91 Iustin Pop
  for dir_name in constants.SUB_RUN_DIRS:
667 195c7f91 Iustin Pop
    if not os.path.exists(dir_name):
668 195c7f91 Iustin Pop
      try:
669 195c7f91 Iustin Pop
        os.mkdir(dir_name, 0755)
670 195c7f91 Iustin Pop
      except EnvironmentError, err:
671 195c7f91 Iustin Pop
        if err.errno != errno.EEXIST:
672 195c7f91 Iustin Pop
          print ("Node setup wrong, cannot create directory %s: %s" %
673 195c7f91 Iustin Pop
                 (dir_name, err))
674 195c7f91 Iustin Pop
          sys.exit(5)
675 195c7f91 Iustin Pop
    if not os.path.isdir(dir_name):
676 195c7f91 Iustin Pop
      print ("Node setup wrong, %s is not a directory" % dir_name)
677 195c7f91 Iustin Pop
      sys.exit(5)
678 0214b0c0 Iustin Pop
679 a8083063 Iustin Pop
  # become a daemon
680 a8083063 Iustin Pop
  if options.fork:
681 8f765069 Iustin Pop
    utils.Daemonize(logfile=constants.LOG_NODESERVER)
682 a8083063 Iustin Pop
683 99e88451 Iustin Pop
  utils.WritePidFile(constants.NODED_PID)
684 73d927a2 Guido Trotter
685 59f187eb Iustin Pop
  logger.SetupLogging(logfile=constants.LOG_NODESERVER, debug=options.debug,
686 59f187eb Iustin Pop
                      stderr_logging=not options.fork)
687 c89189b1 Iustin Pop
  logging.info("ganeti node daemon startup")
688 a8083063 Iustin Pop
689 25d6d12a Michael Hanselmann
  # Prepare job queue
690 25d6d12a Michael Hanselmann
  queue_lock = jstore.InitAndVerifyQueue(must_lock=False)
691 25d6d12a Michael Hanselmann
692 761ce945 Guido Trotter
  if options.fork:
693 84b58db2 Michael Hanselmann
    server = ForkingHTTPServer(('', port))
694 761ce945 Guido Trotter
  else:
695 84b58db2 Michael Hanselmann
    server = NodeDaemonHttpServer(('', port))
696 a8083063 Iustin Pop
697 73d927a2 Guido Trotter
  try:
698 73d927a2 Guido Trotter
    server.serve_forever()
699 73d927a2 Guido Trotter
  finally:
700 99e88451 Iustin Pop
    utils.RemovePidFile(constants.NODED_PID)
701 73d927a2 Guido Trotter
702 a8083063 Iustin Pop
703 3ecf6786 Iustin Pop
if __name__ == '__main__':
704 a8083063 Iustin Pop
  main()