Statistics
| Branch: | Tag: | Revision:

root / daemons / ganeti-noded @ 82d9caef

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