Statistics
| Branch: | Tag: | Revision:

root / daemons / ganeti-noded @ aa9075c5

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