Statistics
| Branch: | Tag: | Revision:

root / daemons / ganeti-noded @ b28a3e8b

History | View | Annotate | Download (18.6 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 74c47259 Iustin Pop
    dev_idx = params[4]
245 74c47259 Iustin Pop
    return backend.ExportSnapshot(disk, dest_node, instance,
246 74c47259 Iustin Pop
                                  cluster_name, dev_idx)
247 3ecf6786 Iustin Pop
248 3ecf6786 Iustin Pop
  @staticmethod
249 3ecf6786 Iustin Pop
  def perspective_finalize_export(params):
250 3ecf6786 Iustin Pop
    """Expose the finalize export functionality.
251 a8083063 Iustin Pop
252 3ecf6786 Iustin Pop
    """
253 319856a9 Michael Hanselmann
    instance = objects.Instance.FromDict(params[0])
254 319856a9 Michael Hanselmann
    snap_disks = [objects.Disk.FromDict(str_data)
255 a8083063 Iustin Pop
                  for str_data in params[1]]
256 a8083063 Iustin Pop
    return backend.FinalizeExport(instance, snap_disks)
257 a8083063 Iustin Pop
258 3ecf6786 Iustin Pop
  @staticmethod
259 3ecf6786 Iustin Pop
  def perspective_export_info(params):
260 3ecf6786 Iustin Pop
    """Query information about an existing export on this node.
261 3ecf6786 Iustin Pop
262 3ecf6786 Iustin Pop
    The given path may not contain an export, in which case we return
263 3ecf6786 Iustin Pop
    None.
264 3ecf6786 Iustin Pop
265 3ecf6786 Iustin Pop
    """
266 3ecf6786 Iustin Pop
    path = params[0]
267 3ecf6786 Iustin Pop
    einfo = backend.ExportInfo(path)
268 a8083063 Iustin Pop
    if einfo is None:
269 a8083063 Iustin Pop
      return einfo
270 a8083063 Iustin Pop
    return einfo.Dumps()
271 a8083063 Iustin Pop
272 3ecf6786 Iustin Pop
  @staticmethod
273 3ecf6786 Iustin Pop
  def perspective_export_list(params):
274 3ecf6786 Iustin Pop
    """List the available exports on this node.
275 3ecf6786 Iustin Pop
276 3ecf6786 Iustin Pop
    Note that as opposed to export_info, which may query data about an
277 3ecf6786 Iustin Pop
    export in any path, this only queries the standard Ganeti path
278 3ecf6786 Iustin Pop
    (constants.EXPORT_DIR).
279 3ecf6786 Iustin Pop
280 3ecf6786 Iustin Pop
    """
281 a8083063 Iustin Pop
    return backend.ListExports()
282 a8083063 Iustin Pop
283 3ecf6786 Iustin Pop
  @staticmethod
284 3ecf6786 Iustin Pop
  def perspective_export_remove(params):
285 3ecf6786 Iustin Pop
    """Remove an export.
286 3ecf6786 Iustin Pop
287 3ecf6786 Iustin Pop
    """
288 a8083063 Iustin Pop
    export = params[0]
289 a8083063 Iustin Pop
    return backend.RemoveExport(export)
290 a8083063 Iustin Pop
291 a8083063 Iustin Pop
  # volume  --------------------------
292 a8083063 Iustin Pop
293 3ecf6786 Iustin Pop
  @staticmethod
294 3ecf6786 Iustin Pop
  def perspective_volume_list(params):
295 3ecf6786 Iustin Pop
    """Query the list of logical volumes in a given volume group.
296 3ecf6786 Iustin Pop
297 3ecf6786 Iustin Pop
    """
298 a8083063 Iustin Pop
    vgname = params[0]
299 a8083063 Iustin Pop
    return backend.GetVolumeList(vgname)
300 a8083063 Iustin Pop
301 3ecf6786 Iustin Pop
  @staticmethod
302 3ecf6786 Iustin Pop
  def perspective_vg_list(params):
303 3ecf6786 Iustin Pop
    """Query the list of volume groups.
304 3ecf6786 Iustin Pop
305 3ecf6786 Iustin Pop
    """
306 a8083063 Iustin Pop
    return backend.ListVolumeGroups()
307 a8083063 Iustin Pop
308 a8083063 Iustin Pop
  # bridge  --------------------------
309 a8083063 Iustin Pop
310 3ecf6786 Iustin Pop
  @staticmethod
311 3ecf6786 Iustin Pop
  def perspective_bridges_exist(params):
312 3ecf6786 Iustin Pop
    """Check if all bridges given exist on this node.
313 3ecf6786 Iustin Pop
314 3ecf6786 Iustin Pop
    """
315 a8083063 Iustin Pop
    bridges_list = params[0]
316 a8083063 Iustin Pop
    return backend.BridgesExist(bridges_list)
317 a8083063 Iustin Pop
318 a8083063 Iustin Pop
  # instance  --------------------------
319 a8083063 Iustin Pop
320 3ecf6786 Iustin Pop
  @staticmethod
321 3ecf6786 Iustin Pop
  def perspective_instance_os_add(params):
322 3ecf6786 Iustin Pop
    """Install an OS on a given instance.
323 3ecf6786 Iustin Pop
324 3ecf6786 Iustin Pop
    """
325 d15a9ad3 Guido Trotter
    inst_s = params[0]
326 319856a9 Michael Hanselmann
    inst = objects.Instance.FromDict(inst_s)
327 d15a9ad3 Guido Trotter
    return backend.AddOSToInstance(inst)
328 a8083063 Iustin Pop
329 3ecf6786 Iustin Pop
  @staticmethod
330 decd5f45 Iustin Pop
  def perspective_instance_run_rename(params):
331 decd5f45 Iustin Pop
    """Runs the OS rename script for an instance.
332 decd5f45 Iustin Pop
333 decd5f45 Iustin Pop
    """
334 d15a9ad3 Guido Trotter
    inst_s, old_name = params
335 319856a9 Michael Hanselmann
    inst = objects.Instance.FromDict(inst_s)
336 d15a9ad3 Guido Trotter
    return backend.RunRenameInstance(inst, old_name)
337 decd5f45 Iustin Pop
338 decd5f45 Iustin Pop
  @staticmethod
339 3ecf6786 Iustin Pop
  def perspective_instance_os_import(params):
340 3ecf6786 Iustin Pop
    """Run the import function of an OS onto a given instance.
341 3ecf6786 Iustin Pop
342 3ecf6786 Iustin Pop
    """
343 6c0af70e Guido Trotter
    inst_s, src_node, src_images, cluster_name = params
344 319856a9 Michael Hanselmann
    inst = objects.Instance.FromDict(inst_s)
345 6c0af70e Guido Trotter
    return backend.ImportOSIntoInstance(inst, src_node, src_images,
346 6c0af70e Guido Trotter
                                        cluster_name)
347 a8083063 Iustin Pop
348 3ecf6786 Iustin Pop
  @staticmethod
349 3ecf6786 Iustin Pop
  def perspective_instance_shutdown(params):
350 3ecf6786 Iustin Pop
    """Shutdown an instance.
351 3ecf6786 Iustin Pop
352 3ecf6786 Iustin Pop
    """
353 319856a9 Michael Hanselmann
    instance = objects.Instance.FromDict(params[0])
354 a8083063 Iustin Pop
    return backend.ShutdownInstance(instance)
355 a8083063 Iustin Pop
356 3ecf6786 Iustin Pop
  @staticmethod
357 3ecf6786 Iustin Pop
  def perspective_instance_start(params):
358 3ecf6786 Iustin Pop
    """Start an instance.
359 3ecf6786 Iustin Pop
360 3ecf6786 Iustin Pop
    """
361 319856a9 Michael Hanselmann
    instance = objects.Instance.FromDict(params[0])
362 a8083063 Iustin Pop
    extra_args = params[1]
363 a8083063 Iustin Pop
    return backend.StartInstance(instance, extra_args)
364 a8083063 Iustin Pop
365 3ecf6786 Iustin Pop
  @staticmethod
366 2a10865c Iustin Pop
  def perspective_instance_migrate(params):
367 2a10865c Iustin Pop
    """Migrates an instance.
368 2a10865c Iustin Pop
369 2a10865c Iustin Pop
    """
370 2a10865c Iustin Pop
    instance, target, live = params
371 9f0e6b37 Iustin Pop
    instance = objects.Instance.FromDict(instance)
372 2a10865c Iustin Pop
    return backend.MigrateInstance(instance, target, live)
373 2a10865c Iustin Pop
374 2a10865c Iustin Pop
  @staticmethod
375 007a2f3e Alexander Schreiber
  def perspective_instance_reboot(params):
376 007a2f3e Alexander Schreiber
    """Reboot an instance.
377 007a2f3e Alexander Schreiber
378 007a2f3e Alexander Schreiber
    """
379 007a2f3e Alexander Schreiber
    instance = objects.Instance.FromDict(params[0])
380 007a2f3e Alexander Schreiber
    reboot_type = params[1]
381 007a2f3e Alexander Schreiber
    extra_args = params[2]
382 007a2f3e Alexander Schreiber
    return backend.RebootInstance(instance, reboot_type, extra_args)
383 007a2f3e Alexander Schreiber
384 007a2f3e Alexander Schreiber
  @staticmethod
385 3ecf6786 Iustin Pop
  def perspective_instance_info(params):
386 3ecf6786 Iustin Pop
    """Query instance information.
387 3ecf6786 Iustin Pop
388 3ecf6786 Iustin Pop
    """
389 16ad1a83 Iustin Pop
    return backend.GetInstanceInfo(params[0], params[1])
390 a8083063 Iustin Pop
391 3ecf6786 Iustin Pop
  @staticmethod
392 3ecf6786 Iustin Pop
  def perspective_all_instances_info(params):
393 3ecf6786 Iustin Pop
    """Query information about all instances.
394 3ecf6786 Iustin Pop
395 3ecf6786 Iustin Pop
    """
396 e69d05fd Iustin Pop
    return backend.GetAllInstancesInfo(params[0])
397 a8083063 Iustin Pop
398 3ecf6786 Iustin Pop
  @staticmethod
399 3ecf6786 Iustin Pop
  def perspective_instance_list(params):
400 3ecf6786 Iustin Pop
    """Query the list of running instances.
401 3ecf6786 Iustin Pop
402 3ecf6786 Iustin Pop
    """
403 e69d05fd Iustin Pop
    return backend.GetInstanceList(params[0])
404 a8083063 Iustin Pop
405 a8083063 Iustin Pop
  # node --------------------------
406 a8083063 Iustin Pop
407 3ecf6786 Iustin Pop
  @staticmethod
408 16abfbc2 Alexander Schreiber
  def perspective_node_tcp_ping(params):
409 16abfbc2 Alexander Schreiber
    """Do a TcpPing on the remote node.
410 16abfbc2 Alexander Schreiber
411 16abfbc2 Alexander Schreiber
    """
412 b15d625f Iustin Pop
    return utils.TcpPing(params[1], params[2], timeout=params[3],
413 b15d625f Iustin Pop
                         live_port_needed=params[4], source=params[0])
414 16abfbc2 Alexander Schreiber
415 16abfbc2 Alexander Schreiber
  @staticmethod
416 caad16e2 Iustin Pop
  def perspective_node_has_ip_address(params):
417 caad16e2 Iustin Pop
    """Checks if a node has the given ip address.
418 caad16e2 Iustin Pop
419 caad16e2 Iustin Pop
    """
420 caad16e2 Iustin Pop
    return utils.OwnIpAddress(params[0])
421 caad16e2 Iustin Pop
422 caad16e2 Iustin Pop
  @staticmethod
423 3ecf6786 Iustin Pop
  def perspective_node_info(params):
424 3ecf6786 Iustin Pop
    """Query node information.
425 3ecf6786 Iustin Pop
426 3ecf6786 Iustin Pop
    """
427 e69d05fd Iustin Pop
    vgname, hypervisor_type = params
428 e69d05fd Iustin Pop
    return backend.GetNodeInfo(vgname, hypervisor_type)
429 a8083063 Iustin Pop
430 3ecf6786 Iustin Pop
  @staticmethod
431 3ecf6786 Iustin Pop
  def perspective_node_add(params):
432 3ecf6786 Iustin Pop
    """Complete the registration of this node in the cluster.
433 3ecf6786 Iustin Pop
434 3ecf6786 Iustin Pop
    """
435 a8083063 Iustin Pop
    return backend.AddNode(params[0], params[1], params[2],
436 a8083063 Iustin Pop
                           params[3], params[4], params[5])
437 a8083063 Iustin Pop
438 3ecf6786 Iustin Pop
  @staticmethod
439 3ecf6786 Iustin Pop
  def perspective_node_verify(params):
440 3ecf6786 Iustin Pop
    """Run a verify sequence on this node.
441 3ecf6786 Iustin Pop
442 3ecf6786 Iustin Pop
    """
443 62c9ec92 Iustin Pop
    return backend.VerifyNode(params[0], params[1])
444 a8083063 Iustin Pop
445 3ecf6786 Iustin Pop
  @staticmethod
446 3ecf6786 Iustin Pop
  def perspective_node_start_master(params):
447 3ecf6786 Iustin Pop
    """Promote this node to master status.
448 3ecf6786 Iustin Pop
449 3ecf6786 Iustin Pop
    """
450 1c65840b Iustin Pop
    return backend.StartMaster(params[0])
451 a8083063 Iustin Pop
452 3ecf6786 Iustin Pop
  @staticmethod
453 3ecf6786 Iustin Pop
  def perspective_node_stop_master(params):
454 3ecf6786 Iustin Pop
    """Demote this node from master status.
455 3ecf6786 Iustin Pop
456 3ecf6786 Iustin Pop
    """
457 1c65840b Iustin Pop
    return backend.StopMaster(params[0])
458 a8083063 Iustin Pop
459 3ecf6786 Iustin Pop
  @staticmethod
460 3ecf6786 Iustin Pop
  def perspective_node_leave_cluster(params):
461 3ecf6786 Iustin Pop
    """Cleanup after leaving a cluster.
462 3ecf6786 Iustin Pop
463 3ecf6786 Iustin Pop
    """
464 a8083063 Iustin Pop
    return backend.LeaveCluster()
465 a8083063 Iustin Pop
466 3ecf6786 Iustin Pop
  @staticmethod
467 3ecf6786 Iustin Pop
  def perspective_node_volumes(params):
468 3ecf6786 Iustin Pop
    """Query the list of all logical volume groups.
469 3ecf6786 Iustin Pop
470 3ecf6786 Iustin Pop
    """
471 dcb93971 Michael Hanselmann
    return backend.NodeVolumes()
472 dcb93971 Michael Hanselmann
473 a8083063 Iustin Pop
  # cluster --------------------------
474 a8083063 Iustin Pop
475 3ecf6786 Iustin Pop
  @staticmethod
476 3ecf6786 Iustin Pop
  def perspective_version(params):
477 3ecf6786 Iustin Pop
    """Query version information.
478 3ecf6786 Iustin Pop
479 3ecf6786 Iustin Pop
    """
480 a8083063 Iustin Pop
    return constants.PROTOCOL_VERSION
481 a8083063 Iustin Pop
482 3ecf6786 Iustin Pop
  @staticmethod
483 3ecf6786 Iustin Pop
  def perspective_upload_file(params):
484 3ecf6786 Iustin Pop
    """Upload a file.
485 3ecf6786 Iustin Pop
486 3ecf6786 Iustin Pop
    Note that the backend implementation imposes strict rules on which
487 3ecf6786 Iustin Pop
    files are accepted.
488 3ecf6786 Iustin Pop
489 3ecf6786 Iustin Pop
    """
490 a8083063 Iustin Pop
    return backend.UploadFile(*params)
491 a8083063 Iustin Pop
492 4e071d3b Iustin Pop
  @staticmethod
493 4e071d3b Iustin Pop
  def perspective_master_info(params):
494 4e071d3b Iustin Pop
    """Query master information.
495 4e071d3b Iustin Pop
496 4e071d3b Iustin Pop
    """
497 4e071d3b Iustin Pop
    return backend.GetMasterInfo()
498 a8083063 Iustin Pop
499 6ddc95ec Michael Hanselmann
  @staticmethod
500 6ddc95ec Michael Hanselmann
  def perspective_write_ssconf_files(params):
501 6ddc95ec Michael Hanselmann
    """Write ssconf files.
502 6ddc95ec Michael Hanselmann
503 6ddc95ec Michael Hanselmann
    """
504 03d1dba2 Michael Hanselmann
    (values,) = params
505 03d1dba2 Michael Hanselmann
    return backend.WriteSsconfFiles(values)
506 6ddc95ec Michael Hanselmann
507 a8083063 Iustin Pop
  # os -----------------------
508 a8083063 Iustin Pop
509 3ecf6786 Iustin Pop
  @staticmethod
510 3ecf6786 Iustin Pop
  def perspective_os_diagnose(params):
511 3ecf6786 Iustin Pop
    """Query detailed information about existing OSes.
512 3ecf6786 Iustin Pop
513 3ecf6786 Iustin Pop
    """
514 4e679f11 Guido Trotter
    return [os.ToDict() for os in backend.DiagnoseOS()]
515 a8083063 Iustin Pop
516 3ecf6786 Iustin Pop
  @staticmethod
517 3ecf6786 Iustin Pop
  def perspective_os_get(params):
518 3ecf6786 Iustin Pop
    """Query information about a given OS.
519 3ecf6786 Iustin Pop
520 3ecf6786 Iustin Pop
    """
521 a8083063 Iustin Pop
    name = params[0]
522 a8083063 Iustin Pop
    try:
523 dfa96ded Guido Trotter
      os_obj = backend.OSFromDisk(name)
524 a8083063 Iustin Pop
    except errors.InvalidOS, err:
525 dfa96ded Guido Trotter
      os_obj = objects.OS.FromInvalidOS(err)
526 dfa96ded Guido Trotter
    return os_obj.ToDict()
527 a8083063 Iustin Pop
528 a8083063 Iustin Pop
  # hooks -----------------------
529 a8083063 Iustin Pop
530 3ecf6786 Iustin Pop
  @staticmethod
531 3ecf6786 Iustin Pop
  def perspective_hooks_runner(params):
532 3ecf6786 Iustin Pop
    """Run hook scripts.
533 3ecf6786 Iustin Pop
534 3ecf6786 Iustin Pop
    """
535 a8083063 Iustin Pop
    hpath, phase, env = params
536 a8083063 Iustin Pop
    hr = backend.HooksRunner()
537 a8083063 Iustin Pop
    return hr.RunHooks(hpath, phase, env)
538 a8083063 Iustin Pop
539 8d528b7c Iustin Pop
  # iallocator -----------------
540 8d528b7c Iustin Pop
541 8d528b7c Iustin Pop
  @staticmethod
542 8d528b7c Iustin Pop
  def perspective_iallocator_runner(params):
543 8d528b7c Iustin Pop
    """Run an iallocator script.
544 8d528b7c Iustin Pop
545 8d528b7c Iustin Pop
    """
546 8d528b7c Iustin Pop
    name, idata = params
547 8d528b7c Iustin Pop
    iar = backend.IAllocatorRunner()
548 8d528b7c Iustin Pop
    return iar.Run(name, idata)
549 8d528b7c Iustin Pop
550 06009e27 Iustin Pop
  # test -----------------------
551 06009e27 Iustin Pop
552 06009e27 Iustin Pop
  @staticmethod
553 06009e27 Iustin Pop
  def perspective_test_delay(params):
554 06009e27 Iustin Pop
    """Run test delay.
555 06009e27 Iustin Pop
556 06009e27 Iustin Pop
    """
557 06009e27 Iustin Pop
    duration = params[0]
558 06009e27 Iustin Pop
    return utils.TestDelay(duration)
559 06009e27 Iustin Pop
560 4e071d3b Iustin Pop
  # file storage ---------------
561 4e071d3b Iustin Pop
562 a5d7fb43 Manuel Franceschini
  @staticmethod
563 a5d7fb43 Manuel Franceschini
  def perspective_file_storage_dir_create(params):
564 a5d7fb43 Manuel Franceschini
    """Create the file storage directory.
565 a5d7fb43 Manuel Franceschini
566 a5d7fb43 Manuel Franceschini
    """
567 a5d7fb43 Manuel Franceschini
    file_storage_dir = params[0]
568 a5d7fb43 Manuel Franceschini
    return backend.CreateFileStorageDir(file_storage_dir)
569 a5d7fb43 Manuel Franceschini
570 a5d7fb43 Manuel Franceschini
  @staticmethod
571 a5d7fb43 Manuel Franceschini
  def perspective_file_storage_dir_remove(params):
572 a5d7fb43 Manuel Franceschini
    """Remove the file storage directory.
573 a5d7fb43 Manuel Franceschini
574 a5d7fb43 Manuel Franceschini
    """
575 a5d7fb43 Manuel Franceschini
    file_storage_dir = params[0]
576 a5d7fb43 Manuel Franceschini
    return backend.RemoveFileStorageDir(file_storage_dir)
577 a5d7fb43 Manuel Franceschini
578 a5d7fb43 Manuel Franceschini
  @staticmethod
579 a5d7fb43 Manuel Franceschini
  def perspective_file_storage_dir_rename(params):
580 a5d7fb43 Manuel Franceschini
    """Rename the file storage directory.
581 a5d7fb43 Manuel Franceschini
582 a5d7fb43 Manuel Franceschini
    """
583 a5d7fb43 Manuel Franceschini
    old_file_storage_dir = params[0]
584 a5d7fb43 Manuel Franceschini
    new_file_storage_dir = params[1]
585 a5d7fb43 Manuel Franceschini
    return backend.RenameFileStorageDir(old_file_storage_dir,
586 a5d7fb43 Manuel Franceschini
                                        new_file_storage_dir)
587 a5d7fb43 Manuel Franceschini
588 4e071d3b Iustin Pop
  # jobs ------------------------
589 4e071d3b Iustin Pop
590 ca52cdeb Michael Hanselmann
  @staticmethod
591 7f30777b Michael Hanselmann
  @_RequireJobQueueLock
592 ca52cdeb Michael Hanselmann
  def perspective_jobqueue_update(params):
593 ca52cdeb Michael Hanselmann
    """Update job queue.
594 ca52cdeb Michael Hanselmann
595 ca52cdeb Michael Hanselmann
    """
596 ca52cdeb Michael Hanselmann
    (file_name, content) = params
597 7f30777b Michael Hanselmann
    return backend.JobQueueUpdate(file_name, content)
598 ca52cdeb Michael Hanselmann
599 ca52cdeb Michael Hanselmann
  @staticmethod
600 f1f3f45c Michael Hanselmann
  @_RequireJobQueueLock
601 ca52cdeb Michael Hanselmann
  def perspective_jobqueue_purge(params):
602 ca52cdeb Michael Hanselmann
    """Purge job queue.
603 ca52cdeb Michael Hanselmann
604 ca52cdeb Michael Hanselmann
    """
605 ca52cdeb Michael Hanselmann
    return backend.JobQueuePurge()
606 ca52cdeb Michael Hanselmann
607 af5ebcb1 Michael Hanselmann
  @staticmethod
608 af5ebcb1 Michael Hanselmann
  @_RequireJobQueueLock
609 af5ebcb1 Michael Hanselmann
  def perspective_jobqueue_rename(params):
610 af5ebcb1 Michael Hanselmann
    """Rename a job queue file.
611 af5ebcb1 Michael Hanselmann
612 af5ebcb1 Michael Hanselmann
    """
613 af5ebcb1 Michael Hanselmann
    (old, new) = params
614 af5ebcb1 Michael Hanselmann
615 af5ebcb1 Michael Hanselmann
    return backend.JobQueueRename(old, new)
616 af5ebcb1 Michael Hanselmann
617 5d672980 Iustin Pop
  @staticmethod
618 5d672980 Iustin Pop
  def perspective_jobqueue_set_drain(params):
619 5d672980 Iustin Pop
    """Set/unset the queue drain flag.
620 5d672980 Iustin Pop
621 5d672980 Iustin Pop
    """
622 5d672980 Iustin Pop
    drain_flag = params[0]
623 5d672980 Iustin Pop
    return backend.JobQueueSetDrainFlag(drain_flag)
624 5d672980 Iustin Pop
625 5d672980 Iustin Pop
626 6217e295 Iustin Pop
  # hypervisor ---------------
627 6217e295 Iustin Pop
628 6217e295 Iustin Pop
  @staticmethod
629 6217e295 Iustin Pop
  def perspective_hypervisor_validate_params(params):
630 6217e295 Iustin Pop
    """Validate the hypervisor parameters.
631 6217e295 Iustin Pop
632 6217e295 Iustin Pop
    """
633 6217e295 Iustin Pop
    (hvname, hvparams) = params
634 6217e295 Iustin Pop
    return backend.ValidateHVParams(hvname, hvparams)
635 6217e295 Iustin Pop
636 a8083063 Iustin Pop
637 a8083063 Iustin Pop
def ParseOptions():
638 a8083063 Iustin Pop
  """Parse the command line options.
639 a8083063 Iustin Pop
640 a8083063 Iustin Pop
  Returns:
641 a8083063 Iustin Pop
    (options, args) as from OptionParser.parse_args()
642 a8083063 Iustin Pop
643 a8083063 Iustin Pop
  """
644 a8083063 Iustin Pop
  parser = OptionParser(description="Ganeti node daemon",
645 a8083063 Iustin Pop
                        usage="%prog [-f] [-d]",
646 a8083063 Iustin Pop
                        version="%%prog (ganeti) %s" %
647 a8083063 Iustin Pop
                        constants.RELEASE_VERSION)
648 a8083063 Iustin Pop
649 a8083063 Iustin Pop
  parser.add_option("-f", "--foreground", dest="fork",
650 a8083063 Iustin Pop
                    help="Don't detach from the current terminal",
651 a8083063 Iustin Pop
                    default=True, action="store_false")
652 a8083063 Iustin Pop
  parser.add_option("-d", "--debug", dest="debug",
653 a8083063 Iustin Pop
                    help="Enable some debug messages",
654 a8083063 Iustin Pop
                    default=False, action="store_true")
655 a8083063 Iustin Pop
  options, args = parser.parse_args()
656 a8083063 Iustin Pop
  return options, args
657 a8083063 Iustin Pop
658 a8083063 Iustin Pop
659 8adbffaa Iustin Pop
def EnsureRuntimeEnvironment():
660 8adbffaa Iustin Pop
  """Ensure our run-time environment is complete.
661 8adbffaa Iustin Pop
662 8adbffaa Iustin Pop
  Currently this creates directories which could be missing, either
663 8adbffaa Iustin Pop
  due to directories being on a tmpfs mount, or due to incomplete
664 8adbffaa Iustin Pop
  packaging.
665 8adbffaa Iustin Pop
666 8adbffaa Iustin Pop
  """
667 817a030d Guido Trotter
  dirs = [(val, constants.RUN_DIRS_MODE) for val in constants.SUB_RUN_DIRS]
668 8adbffaa Iustin Pop
  dirs.append((constants.LOG_OS_DIR, 0750))
669 8adbffaa Iustin Pop
  for dir_name, dir_mode in dirs:
670 8adbffaa Iustin Pop
    if not os.path.exists(dir_name):
671 8adbffaa Iustin Pop
      try:
672 8adbffaa Iustin Pop
        os.mkdir(dir_name, dir_mode)
673 8adbffaa Iustin Pop
      except EnvironmentError, err:
674 8adbffaa Iustin Pop
        if err.errno != errno.EEXIST:
675 8adbffaa Iustin Pop
          print ("Node setup wrong, cannot create directory '%s': %s" %
676 8adbffaa Iustin Pop
                 (dir_name, err))
677 8adbffaa Iustin Pop
          sys.exit(5)
678 8adbffaa Iustin Pop
    if not os.path.isdir(dir_name):
679 8adbffaa Iustin Pop
      print ("Node setup wrong, '%s' is not a directory" % dir_name)
680 8adbffaa Iustin Pop
      sys.exit(5)
681 8adbffaa Iustin Pop
682 8adbffaa Iustin Pop
683 a8083063 Iustin Pop
def main():
684 3ecf6786 Iustin Pop
  """Main function for the node daemon.
685 3ecf6786 Iustin Pop
686 3ecf6786 Iustin Pop
  """
687 25d6d12a Michael Hanselmann
  global queue_lock
688 25d6d12a Michael Hanselmann
689 a8083063 Iustin Pop
  options, args = ParseOptions()
690 f362096f Iustin Pop
  utils.debug = options.debug
691 a8083063 Iustin Pop
  for fname in (constants.SSL_CERT_FILE,):
692 a8083063 Iustin Pop
    if not os.path.isfile(fname):
693 a8083063 Iustin Pop
      print "config %s not there, will not run." % fname
694 a8083063 Iustin Pop
      sys.exit(5)
695 a8083063 Iustin Pop
696 a8083063 Iustin Pop
  try:
697 8594f271 Michael Hanselmann
    port = utils.GetNodeDaemonPort()
698 a8083063 Iustin Pop
  except errors.ConfigurationError, err:
699 a8083063 Iustin Pop
    print "Cluster configuration incomplete: '%s'" % str(err)
700 a8083063 Iustin Pop
    sys.exit(5)
701 a8083063 Iustin Pop
702 8adbffaa Iustin Pop
  EnsureRuntimeEnvironment()
703 0214b0c0 Iustin Pop
704 a8083063 Iustin Pop
  # become a daemon
705 a8083063 Iustin Pop
  if options.fork:
706 8f765069 Iustin Pop
    utils.Daemonize(logfile=constants.LOG_NODESERVER)
707 a8083063 Iustin Pop
708 99e88451 Iustin Pop
  utils.WritePidFile(constants.NODED_PID)
709 cc28af80 Michael Hanselmann
  try:
710 82d9caef Iustin Pop
    utils.SetupLogging(logfile=constants.LOG_NODESERVER, debug=options.debug,
711 82d9caef Iustin Pop
                       stderr_logging=not options.fork)
712 cc28af80 Michael Hanselmann
    logging.info("ganeti node daemon startup")
713 73d927a2 Guido Trotter
714 eafd8762 Michael Hanselmann
    # Read SSL certificate
715 eafd8762 Michael Hanselmann
    ssl_params = http.HttpSslParams(ssl_key_path=constants.SSL_CERT_FILE,
716 eafd8762 Michael Hanselmann
                                    ssl_cert_path=constants.SSL_CERT_FILE)
717 eafd8762 Michael Hanselmann
718 cc28af80 Michael Hanselmann
    # Prepare job queue
719 cc28af80 Michael Hanselmann
    queue_lock = jstore.InitAndVerifyQueue(must_lock=False)
720 a8083063 Iustin Pop
721 cc28af80 Michael Hanselmann
    mainloop = daemon.Mainloop()
722 eafd8762 Michael Hanselmann
    server = NodeHttpServer(mainloop, "", port,
723 eafd8762 Michael Hanselmann
                            ssl_params=ssl_params, ssl_verify_peer=True)
724 cc28af80 Michael Hanselmann
    server.Start()
725 cc28af80 Michael Hanselmann
    try:
726 cc28af80 Michael Hanselmann
      mainloop.Run()
727 cc28af80 Michael Hanselmann
    finally:
728 cc28af80 Michael Hanselmann
      server.Stop()
729 73d927a2 Guido Trotter
  finally:
730 99e88451 Iustin Pop
    utils.RemovePidFile(constants.NODED_PID)
731 73d927a2 Guido Trotter
732 a8083063 Iustin Pop
733 3ecf6786 Iustin Pop
if __name__ == '__main__':
734 a8083063 Iustin Pop
  main()