Statistics
| Branch: | Tag: | Revision:

root / daemons / ganeti-noded @ af5ebcb1

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