Statistics
| Branch: | Tag: | Revision:

root / daemons / ganeti-noded @ 25d6d12a

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