Statistics
| Branch: | Tag: | Revision:

root / daemons / ganeti-noded @ 59f187eb

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