Statistics
| Branch: | Tag: | Revision:

root / daemons / ganeti-noded @ b2e7666a

History | View | Annotate | Download (18.9 kB)

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