Statistics
| Branch: | Tag: | Revision:

root / daemons / ganeti-noded @ d15a9ad3

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