Statistics
| Branch: | Tag: | Revision:

root / daemons / ganeti-noded @ 17dfc522

History | View | Annotate | Download (16.4 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 resource
30 a8083063 Iustin Pop
import traceback
31 81010134 Iustin Pop
import BaseHTTPServer
32 81010134 Iustin Pop
import simplejson
33 0214b0c0 Iustin Pop
import errno
34 a8083063 Iustin Pop
35 a8083063 Iustin Pop
from optparse import OptionParser
36 a8083063 Iustin Pop
37 a8083063 Iustin Pop
38 a8083063 Iustin Pop
from ganeti import backend
39 a8083063 Iustin Pop
from ganeti import logger
40 a8083063 Iustin Pop
from ganeti import constants
41 a8083063 Iustin Pop
from ganeti import objects
42 a8083063 Iustin Pop
from ganeti import errors
43 a8083063 Iustin Pop
from ganeti import ssconf
44 16abfbc2 Alexander Schreiber
from ganeti import utils
45 a8083063 Iustin Pop
46 a8083063 Iustin Pop
47 81010134 Iustin Pop
class ServerObject(BaseHTTPServer.BaseHTTPRequestHandler):
48 3ecf6786 Iustin Pop
  """The server implementation.
49 3ecf6786 Iustin Pop
50 3ecf6786 Iustin Pop
  This class holds all methods exposed over the RPC interface.
51 3ecf6786 Iustin Pop
52 3ecf6786 Iustin Pop
  """
53 81010134 Iustin Pop
  def do_PUT(self):
54 81010134 Iustin Pop
    """Handle a post request.
55 a8083063 Iustin Pop
56 098c0958 Michael Hanselmann
    """
57 81010134 Iustin Pop
    path = self.path
58 81010134 Iustin Pop
    if path.startswith("/"):
59 81010134 Iustin Pop
      path = path[1:]
60 81010134 Iustin Pop
    mname = "perspective_%s" % path
61 81010134 Iustin Pop
    if not hasattr(self, mname):
62 81010134 Iustin Pop
      self.send_error(404)
63 81010134 Iustin Pop
      return False
64 81010134 Iustin Pop
65 81010134 Iustin Pop
    method = getattr(self, mname)
66 a8083063 Iustin Pop
    try:
67 81010134 Iustin Pop
      body_length = int(self.headers.get('Content-Length', '0'))
68 81010134 Iustin Pop
    except ValueError:
69 81010134 Iustin Pop
      self.send_error(400, 'No Content-Length header or invalid format')
70 81010134 Iustin Pop
      return False
71 a8083063 Iustin Pop
72 81010134 Iustin Pop
    try:
73 81010134 Iustin Pop
      body = self.rfile.read(body_length)
74 81010134 Iustin Pop
    except socket.error, err:
75 81010134 Iustin Pop
      logger.Error("Socket error while reading: %s" % str(err))
76 81010134 Iustin Pop
      return
77 81010134 Iustin Pop
    try:
78 81010134 Iustin Pop
      params = simplejson.loads(body)
79 81010134 Iustin Pop
      result = method(params)
80 81010134 Iustin Pop
      payload = simplejson.dumps(result)
81 81010134 Iustin Pop
    except Exception, err:
82 81010134 Iustin Pop
      self.send_error(500, "Error: %s" % str(err))
83 81010134 Iustin Pop
      return False
84 81010134 Iustin Pop
    self.send_response(200)
85 81010134 Iustin Pop
    self.send_header('Content-Length', str(len(payload)))
86 81010134 Iustin Pop
    self.end_headers()
87 81010134 Iustin Pop
    self.wfile.write(payload)
88 81010134 Iustin Pop
    return True
89 81010134 Iustin Pop
90 81010134 Iustin Pop
  def log_message(self, format, *args):
91 81010134 Iustin Pop
    """Log a request to the log.
92 81010134 Iustin Pop
93 81010134 Iustin Pop
    This is the same as the parent, we just log somewhere else.
94 81010134 Iustin Pop
95 81010134 Iustin Pop
    """
96 81010134 Iustin Pop
    msg = ("%s - - [%s] %s\n" %
97 81010134 Iustin Pop
           (self.address_string(),
98 81010134 Iustin Pop
            self.log_date_time_string(),
99 81010134 Iustin Pop
            format % args))
100 81010134 Iustin Pop
    logger.Debug(msg)
101 a8083063 Iustin Pop
102 a8083063 Iustin Pop
  # the new block devices  --------------------------
103 a8083063 Iustin Pop
104 3ecf6786 Iustin Pop
  @staticmethod
105 3ecf6786 Iustin Pop
  def perspective_blockdev_create(params):
106 3ecf6786 Iustin Pop
    """Create a block device.
107 3ecf6786 Iustin Pop
108 3ecf6786 Iustin Pop
    """
109 3f78eef2 Iustin Pop
    bdev_s, size, owner, on_primary, info = params
110 319856a9 Michael Hanselmann
    bdev = objects.Disk.FromDict(bdev_s)
111 a8083063 Iustin Pop
    if bdev is None:
112 a8083063 Iustin Pop
      raise ValueError("can't unserialize data!")
113 3f78eef2 Iustin Pop
    return backend.CreateBlockDevice(bdev, size, owner, on_primary, info)
114 a8083063 Iustin Pop
115 3ecf6786 Iustin Pop
  @staticmethod
116 3ecf6786 Iustin Pop
  def perspective_blockdev_remove(params):
117 3ecf6786 Iustin Pop
    """Remove a block device.
118 3ecf6786 Iustin Pop
119 3ecf6786 Iustin Pop
    """
120 a8083063 Iustin Pop
    bdev_s = params[0]
121 319856a9 Michael Hanselmann
    bdev = objects.Disk.FromDict(bdev_s)
122 a8083063 Iustin Pop
    return backend.RemoveBlockDevice(bdev)
123 a8083063 Iustin Pop
124 3ecf6786 Iustin Pop
  @staticmethod
125 f3e513ad Iustin Pop
  def perspective_blockdev_rename(params):
126 f3e513ad Iustin Pop
    """Remove a block device.
127 f3e513ad Iustin Pop
128 f3e513ad Iustin Pop
    """
129 f3e513ad Iustin Pop
    devlist = [(objects.Disk.FromDict(ds), uid) for ds, uid in params]
130 f3e513ad Iustin Pop
    return backend.RenameBlockDevices(devlist)
131 f3e513ad Iustin Pop
132 f3e513ad Iustin Pop
  @staticmethod
133 3ecf6786 Iustin Pop
  def perspective_blockdev_assemble(params):
134 3ecf6786 Iustin Pop
    """Assemble a block device.
135 3ecf6786 Iustin Pop
136 3ecf6786 Iustin Pop
    """
137 3f78eef2 Iustin Pop
    bdev_s, owner, on_primary = params
138 319856a9 Michael Hanselmann
    bdev = objects.Disk.FromDict(bdev_s)
139 a8083063 Iustin Pop
    if bdev is None:
140 a8083063 Iustin Pop
      raise ValueError("can't unserialize data!")
141 3f78eef2 Iustin Pop
    return backend.AssembleBlockDevice(bdev, owner, on_primary)
142 a8083063 Iustin Pop
143 3ecf6786 Iustin Pop
  @staticmethod
144 3ecf6786 Iustin Pop
  def perspective_blockdev_shutdown(params):
145 3ecf6786 Iustin Pop
    """Shutdown a block device.
146 3ecf6786 Iustin Pop
147 3ecf6786 Iustin Pop
    """
148 a8083063 Iustin Pop
    bdev_s = params[0]
149 319856a9 Michael Hanselmann
    bdev = objects.Disk.FromDict(bdev_s)
150 a8083063 Iustin Pop
    if bdev is None:
151 a8083063 Iustin Pop
      raise ValueError("can't unserialize data!")
152 a8083063 Iustin Pop
    return backend.ShutdownBlockDevice(bdev)
153 a8083063 Iustin Pop
154 3ecf6786 Iustin Pop
  @staticmethod
155 153d9724 Iustin Pop
  def perspective_blockdev_addchildren(params):
156 3ecf6786 Iustin Pop
    """Add a child to a mirror device.
157 3ecf6786 Iustin Pop
158 3ecf6786 Iustin Pop
    Note: this is only valid for mirror devices. It's the caller's duty
159 3ecf6786 Iustin Pop
    to send a correct disk, otherwise we raise an error.
160 3ecf6786 Iustin Pop
161 3ecf6786 Iustin Pop
    """
162 a8083063 Iustin Pop
    bdev_s, ndev_s = params
163 319856a9 Michael Hanselmann
    bdev = objects.Disk.FromDict(bdev_s)
164 153d9724 Iustin Pop
    ndevs = [objects.Disk.FromDict(disk_s) for disk_s in ndev_s]
165 153d9724 Iustin Pop
    if bdev is None or ndevs.count(None) > 0:
166 a8083063 Iustin Pop
      raise ValueError("can't unserialize data!")
167 153d9724 Iustin Pop
    return backend.MirrorAddChildren(bdev, ndevs)
168 a8083063 Iustin Pop
169 3ecf6786 Iustin Pop
  @staticmethod
170 153d9724 Iustin Pop
  def perspective_blockdev_removechildren(params):
171 3ecf6786 Iustin Pop
    """Remove a child from a mirror device.
172 3ecf6786 Iustin Pop
173 3ecf6786 Iustin Pop
    This is only valid for mirror devices, of course. It's the callers
174 3ecf6786 Iustin Pop
    duty to send a correct disk, otherwise we raise an error.
175 3ecf6786 Iustin Pop
176 3ecf6786 Iustin Pop
    """
177 a8083063 Iustin Pop
    bdev_s, ndev_s = params
178 319856a9 Michael Hanselmann
    bdev = objects.Disk.FromDict(bdev_s)
179 153d9724 Iustin Pop
    ndevs = [objects.Disk.FromDict(disk_s) for disk_s in ndev_s]
180 153d9724 Iustin Pop
    if bdev is None or ndevs.count(None) > 0:
181 a8083063 Iustin Pop
      raise ValueError("can't unserialize data!")
182 153d9724 Iustin Pop
    return backend.MirrorRemoveChildren(bdev, ndevs)
183 a8083063 Iustin Pop
184 3ecf6786 Iustin Pop
  @staticmethod
185 3ecf6786 Iustin Pop
  def perspective_blockdev_getmirrorstatus(params):
186 3ecf6786 Iustin Pop
    """Return the mirror status for a list of disks.
187 3ecf6786 Iustin Pop
188 3ecf6786 Iustin Pop
    """
189 319856a9 Michael Hanselmann
    disks = [objects.Disk.FromDict(dsk_s)
190 a8083063 Iustin Pop
            for dsk_s in params]
191 a8083063 Iustin Pop
    return backend.GetMirrorStatus(disks)
192 a8083063 Iustin Pop
193 3ecf6786 Iustin Pop
  @staticmethod
194 3ecf6786 Iustin Pop
  def perspective_blockdev_find(params):
195 3ecf6786 Iustin Pop
    """Expose the FindBlockDevice functionality for a disk.
196 3ecf6786 Iustin Pop
197 3ecf6786 Iustin Pop
    This will try to find but not activate a disk.
198 3ecf6786 Iustin Pop
199 3ecf6786 Iustin Pop
    """
200 319856a9 Michael Hanselmann
    disk = objects.Disk.FromDict(params[0])
201 a8083063 Iustin Pop
    return backend.FindBlockDevice(disk)
202 a8083063 Iustin Pop
203 3ecf6786 Iustin Pop
  @staticmethod
204 3ecf6786 Iustin Pop
  def perspective_blockdev_snapshot(params):
205 3ecf6786 Iustin Pop
    """Create a snapshot device.
206 3ecf6786 Iustin Pop
207 3ecf6786 Iustin Pop
    Note that this is only valid for LVM disks, if we get passed
208 3ecf6786 Iustin Pop
    something else we raise an exception. The snapshot device can be
209 3ecf6786 Iustin Pop
    remove by calling the generic block device remove call.
210 3ecf6786 Iustin Pop
211 3ecf6786 Iustin Pop
    """
212 319856a9 Michael Hanselmann
    cfbd = objects.Disk.FromDict(params[0])
213 a8083063 Iustin Pop
    return backend.SnapshotBlockDevice(cfbd)
214 a8083063 Iustin Pop
215 a8083063 Iustin Pop
  # export/import  --------------------------
216 a8083063 Iustin Pop
217 3ecf6786 Iustin Pop
  @staticmethod
218 3ecf6786 Iustin Pop
  def perspective_snapshot_export(params):
219 3ecf6786 Iustin Pop
    """Export a given snapshot.
220 3ecf6786 Iustin Pop
221 3ecf6786 Iustin Pop
    """
222 319856a9 Michael Hanselmann
    disk = objects.Disk.FromDict(params[0])
223 a8083063 Iustin Pop
    dest_node = params[1]
224 319856a9 Michael Hanselmann
    instance = objects.Instance.FromDict(params[2])
225 3ecf6786 Iustin Pop
    return backend.ExportSnapshot(disk, dest_node, instance)
226 3ecf6786 Iustin Pop
227 3ecf6786 Iustin Pop
  @staticmethod
228 3ecf6786 Iustin Pop
  def perspective_finalize_export(params):
229 3ecf6786 Iustin Pop
    """Expose the finalize export functionality.
230 a8083063 Iustin Pop
231 3ecf6786 Iustin Pop
    """
232 319856a9 Michael Hanselmann
    instance = objects.Instance.FromDict(params[0])
233 319856a9 Michael Hanselmann
    snap_disks = [objects.Disk.FromDict(str_data)
234 a8083063 Iustin Pop
                  for str_data in params[1]]
235 a8083063 Iustin Pop
    return backend.FinalizeExport(instance, snap_disks)
236 a8083063 Iustin Pop
237 3ecf6786 Iustin Pop
  @staticmethod
238 3ecf6786 Iustin Pop
  def perspective_export_info(params):
239 3ecf6786 Iustin Pop
    """Query information about an existing export on this node.
240 3ecf6786 Iustin Pop
241 3ecf6786 Iustin Pop
    The given path may not contain an export, in which case we return
242 3ecf6786 Iustin Pop
    None.
243 3ecf6786 Iustin Pop
244 3ecf6786 Iustin Pop
    """
245 3ecf6786 Iustin Pop
    path = params[0]
246 3ecf6786 Iustin Pop
    einfo = backend.ExportInfo(path)
247 a8083063 Iustin Pop
    if einfo is None:
248 a8083063 Iustin Pop
      return einfo
249 a8083063 Iustin Pop
    return einfo.Dumps()
250 a8083063 Iustin Pop
251 3ecf6786 Iustin Pop
  @staticmethod
252 3ecf6786 Iustin Pop
  def perspective_export_list(params):
253 3ecf6786 Iustin Pop
    """List the available exports on this node.
254 3ecf6786 Iustin Pop
255 3ecf6786 Iustin Pop
    Note that as opposed to export_info, which may query data about an
256 3ecf6786 Iustin Pop
    export in any path, this only queries the standard Ganeti path
257 3ecf6786 Iustin Pop
    (constants.EXPORT_DIR).
258 3ecf6786 Iustin Pop
259 3ecf6786 Iustin Pop
    """
260 a8083063 Iustin Pop
    return backend.ListExports()
261 a8083063 Iustin Pop
262 3ecf6786 Iustin Pop
  @staticmethod
263 3ecf6786 Iustin Pop
  def perspective_export_remove(params):
264 3ecf6786 Iustin Pop
    """Remove an export.
265 3ecf6786 Iustin Pop
266 3ecf6786 Iustin Pop
    """
267 a8083063 Iustin Pop
    export = params[0]
268 a8083063 Iustin Pop
    return backend.RemoveExport(export)
269 a8083063 Iustin Pop
270 a8083063 Iustin Pop
  # volume  --------------------------
271 a8083063 Iustin Pop
272 3ecf6786 Iustin Pop
  @staticmethod
273 3ecf6786 Iustin Pop
  def perspective_volume_list(params):
274 3ecf6786 Iustin Pop
    """Query the list of logical volumes in a given volume group.
275 3ecf6786 Iustin Pop
276 3ecf6786 Iustin Pop
    """
277 a8083063 Iustin Pop
    vgname = params[0]
278 a8083063 Iustin Pop
    return backend.GetVolumeList(vgname)
279 a8083063 Iustin Pop
280 3ecf6786 Iustin Pop
  @staticmethod
281 3ecf6786 Iustin Pop
  def perspective_vg_list(params):
282 3ecf6786 Iustin Pop
    """Query the list of volume groups.
283 3ecf6786 Iustin Pop
284 3ecf6786 Iustin Pop
    """
285 a8083063 Iustin Pop
    return backend.ListVolumeGroups()
286 a8083063 Iustin Pop
287 a8083063 Iustin Pop
  # bridge  --------------------------
288 a8083063 Iustin Pop
289 3ecf6786 Iustin Pop
  @staticmethod
290 3ecf6786 Iustin Pop
  def perspective_bridges_exist(params):
291 3ecf6786 Iustin Pop
    """Check if all bridges given exist on this node.
292 3ecf6786 Iustin Pop
293 3ecf6786 Iustin Pop
    """
294 a8083063 Iustin Pop
    bridges_list = params[0]
295 a8083063 Iustin Pop
    return backend.BridgesExist(bridges_list)
296 a8083063 Iustin Pop
297 a8083063 Iustin Pop
  # instance  --------------------------
298 a8083063 Iustin Pop
299 3ecf6786 Iustin Pop
  @staticmethod
300 3ecf6786 Iustin Pop
  def perspective_instance_os_add(params):
301 3ecf6786 Iustin Pop
    """Install an OS on a given instance.
302 3ecf6786 Iustin Pop
303 3ecf6786 Iustin Pop
    """
304 a8083063 Iustin Pop
    inst_s, os_disk, swap_disk = params
305 319856a9 Michael Hanselmann
    inst = objects.Instance.FromDict(inst_s)
306 a8083063 Iustin Pop
    return backend.AddOSToInstance(inst, os_disk, swap_disk)
307 a8083063 Iustin Pop
308 3ecf6786 Iustin Pop
  @staticmethod
309 decd5f45 Iustin Pop
  def perspective_instance_run_rename(params):
310 decd5f45 Iustin Pop
    """Runs the OS rename script for an instance.
311 decd5f45 Iustin Pop
312 decd5f45 Iustin Pop
    """
313 decd5f45 Iustin Pop
    inst_s, old_name, os_disk, swap_disk = params
314 319856a9 Michael Hanselmann
    inst = objects.Instance.FromDict(inst_s)
315 decd5f45 Iustin Pop
    return backend.RunRenameInstance(inst, old_name, os_disk, swap_disk)
316 decd5f45 Iustin Pop
317 decd5f45 Iustin Pop
  @staticmethod
318 3ecf6786 Iustin Pop
  def perspective_instance_os_import(params):
319 3ecf6786 Iustin Pop
    """Run the import function of an OS onto a given instance.
320 3ecf6786 Iustin Pop
321 3ecf6786 Iustin Pop
    """
322 a8083063 Iustin Pop
    inst_s, os_disk, swap_disk, src_node, src_image = params
323 319856a9 Michael Hanselmann
    inst = objects.Instance.FromDict(inst_s)
324 a8083063 Iustin Pop
    return backend.ImportOSIntoInstance(inst, os_disk, swap_disk,
325 a8083063 Iustin Pop
                                        src_node, src_image)
326 a8083063 Iustin Pop
327 3ecf6786 Iustin Pop
  @staticmethod
328 3ecf6786 Iustin Pop
  def perspective_instance_shutdown(params):
329 3ecf6786 Iustin Pop
    """Shutdown an instance.
330 3ecf6786 Iustin Pop
331 3ecf6786 Iustin Pop
    """
332 319856a9 Michael Hanselmann
    instance = objects.Instance.FromDict(params[0])
333 a8083063 Iustin Pop
    return backend.ShutdownInstance(instance)
334 a8083063 Iustin Pop
335 3ecf6786 Iustin Pop
  @staticmethod
336 3ecf6786 Iustin Pop
  def perspective_instance_start(params):
337 3ecf6786 Iustin Pop
    """Start an instance.
338 3ecf6786 Iustin Pop
339 3ecf6786 Iustin Pop
    """
340 319856a9 Michael Hanselmann
    instance = objects.Instance.FromDict(params[0])
341 a8083063 Iustin Pop
    extra_args = params[1]
342 a8083063 Iustin Pop
    return backend.StartInstance(instance, extra_args)
343 a8083063 Iustin Pop
344 3ecf6786 Iustin Pop
  @staticmethod
345 007a2f3e Alexander Schreiber
  def perspective_instance_reboot(params):
346 007a2f3e Alexander Schreiber
    """Reboot an instance.
347 007a2f3e Alexander Schreiber
348 007a2f3e Alexander Schreiber
    """
349 007a2f3e Alexander Schreiber
    instance = objects.Instance.FromDict(params[0])
350 007a2f3e Alexander Schreiber
    reboot_type = params[1]
351 007a2f3e Alexander Schreiber
    extra_args = params[2]
352 007a2f3e Alexander Schreiber
    return backend.RebootInstance(instance, reboot_type, extra_args)
353 007a2f3e Alexander Schreiber
354 007a2f3e Alexander Schreiber
  @staticmethod
355 3ecf6786 Iustin Pop
  def perspective_instance_info(params):
356 3ecf6786 Iustin Pop
    """Query instance information.
357 3ecf6786 Iustin Pop
358 3ecf6786 Iustin Pop
    """
359 a8083063 Iustin Pop
    return backend.GetInstanceInfo(params[0])
360 a8083063 Iustin Pop
361 3ecf6786 Iustin Pop
  @staticmethod
362 3ecf6786 Iustin Pop
  def perspective_all_instances_info(params):
363 3ecf6786 Iustin Pop
    """Query information about all instances.
364 3ecf6786 Iustin Pop
365 3ecf6786 Iustin Pop
    """
366 a8083063 Iustin Pop
    return backend.GetAllInstancesInfo()
367 a8083063 Iustin Pop
368 3ecf6786 Iustin Pop
  @staticmethod
369 3ecf6786 Iustin Pop
  def perspective_instance_list(params):
370 3ecf6786 Iustin Pop
    """Query the list of running instances.
371 3ecf6786 Iustin Pop
372 3ecf6786 Iustin Pop
    """
373 a8083063 Iustin Pop
    return backend.GetInstanceList()
374 a8083063 Iustin Pop
375 a8083063 Iustin Pop
  # node --------------------------
376 a8083063 Iustin Pop
377 3ecf6786 Iustin Pop
  @staticmethod
378 16abfbc2 Alexander Schreiber
  def perspective_node_tcp_ping(params):
379 16abfbc2 Alexander Schreiber
    """Do a TcpPing on the remote node.
380 16abfbc2 Alexander Schreiber
381 16abfbc2 Alexander Schreiber
    """
382 b15d625f Iustin Pop
    return utils.TcpPing(params[1], params[2], timeout=params[3],
383 b15d625f Iustin Pop
                         live_port_needed=params[4], source=params[0])
384 16abfbc2 Alexander Schreiber
385 16abfbc2 Alexander Schreiber
  @staticmethod
386 3ecf6786 Iustin Pop
  def perspective_node_info(params):
387 3ecf6786 Iustin Pop
    """Query node information.
388 3ecf6786 Iustin Pop
389 3ecf6786 Iustin Pop
    """
390 a8083063 Iustin Pop
    vgname = params[0]
391 a8083063 Iustin Pop
    return backend.GetNodeInfo(vgname)
392 a8083063 Iustin Pop
393 3ecf6786 Iustin Pop
  @staticmethod
394 3ecf6786 Iustin Pop
  def perspective_node_add(params):
395 3ecf6786 Iustin Pop
    """Complete the registration of this node in the cluster.
396 3ecf6786 Iustin Pop
397 3ecf6786 Iustin Pop
    """
398 a8083063 Iustin Pop
    return backend.AddNode(params[0], params[1], params[2],
399 a8083063 Iustin Pop
                           params[3], params[4], params[5])
400 a8083063 Iustin Pop
401 3ecf6786 Iustin Pop
  @staticmethod
402 3ecf6786 Iustin Pop
  def perspective_node_verify(params):
403 3ecf6786 Iustin Pop
    """Run a verify sequence on this node.
404 3ecf6786 Iustin Pop
405 3ecf6786 Iustin Pop
    """
406 a8083063 Iustin Pop
    return backend.VerifyNode(params[0])
407 a8083063 Iustin Pop
408 3ecf6786 Iustin Pop
  @staticmethod
409 3ecf6786 Iustin Pop
  def perspective_node_start_master(params):
410 3ecf6786 Iustin Pop
    """Promote this node to master status.
411 3ecf6786 Iustin Pop
412 3ecf6786 Iustin Pop
    """
413 a8083063 Iustin Pop
    return backend.StartMaster()
414 a8083063 Iustin Pop
415 3ecf6786 Iustin Pop
  @staticmethod
416 3ecf6786 Iustin Pop
  def perspective_node_stop_master(params):
417 3ecf6786 Iustin Pop
    """Demote this node from master status.
418 3ecf6786 Iustin Pop
419 3ecf6786 Iustin Pop
    """
420 a8083063 Iustin Pop
    return backend.StopMaster()
421 a8083063 Iustin Pop
422 3ecf6786 Iustin Pop
  @staticmethod
423 3ecf6786 Iustin Pop
  def perspective_node_leave_cluster(params):
424 3ecf6786 Iustin Pop
    """Cleanup after leaving a cluster.
425 3ecf6786 Iustin Pop
426 3ecf6786 Iustin Pop
    """
427 a8083063 Iustin Pop
    return backend.LeaveCluster()
428 a8083063 Iustin Pop
429 3ecf6786 Iustin Pop
  @staticmethod
430 3ecf6786 Iustin Pop
  def perspective_node_volumes(params):
431 3ecf6786 Iustin Pop
    """Query the list of all logical volume groups.
432 3ecf6786 Iustin Pop
433 3ecf6786 Iustin Pop
    """
434 dcb93971 Michael Hanselmann
    return backend.NodeVolumes()
435 dcb93971 Michael Hanselmann
436 a8083063 Iustin Pop
  # cluster --------------------------
437 a8083063 Iustin Pop
438 3ecf6786 Iustin Pop
  @staticmethod
439 3ecf6786 Iustin Pop
  def perspective_version(params):
440 3ecf6786 Iustin Pop
    """Query version information.
441 3ecf6786 Iustin Pop
442 3ecf6786 Iustin Pop
    """
443 a8083063 Iustin Pop
    return constants.PROTOCOL_VERSION
444 a8083063 Iustin Pop
445 3ecf6786 Iustin Pop
  @staticmethod
446 3ecf6786 Iustin Pop
  def perspective_upload_file(params):
447 3ecf6786 Iustin Pop
    """Upload a file.
448 3ecf6786 Iustin Pop
449 3ecf6786 Iustin Pop
    Note that the backend implementation imposes strict rules on which
450 3ecf6786 Iustin Pop
    files are accepted.
451 3ecf6786 Iustin Pop
452 3ecf6786 Iustin Pop
    """
453 a8083063 Iustin Pop
    return backend.UploadFile(*params)
454 a8083063 Iustin Pop
455 a8083063 Iustin Pop
456 a8083063 Iustin Pop
  # os -----------------------
457 a8083063 Iustin Pop
458 3ecf6786 Iustin Pop
  @staticmethod
459 3ecf6786 Iustin Pop
  def perspective_os_diagnose(params):
460 3ecf6786 Iustin Pop
    """Query detailed information about existing OSes.
461 3ecf6786 Iustin Pop
462 3ecf6786 Iustin Pop
    """
463 4e679f11 Guido Trotter
    return [os.ToDict() for os in backend.DiagnoseOS()]
464 a8083063 Iustin Pop
465 3ecf6786 Iustin Pop
  @staticmethod
466 3ecf6786 Iustin Pop
  def perspective_os_get(params):
467 3ecf6786 Iustin Pop
    """Query information about a given OS.
468 3ecf6786 Iustin Pop
469 3ecf6786 Iustin Pop
    """
470 a8083063 Iustin Pop
    name = params[0]
471 a8083063 Iustin Pop
    try:
472 dfa96ded Guido Trotter
      os_obj = backend.OSFromDisk(name)
473 a8083063 Iustin Pop
    except errors.InvalidOS, err:
474 dfa96ded Guido Trotter
      os_obj = objects.OS.FromInvalidOS(err)
475 dfa96ded Guido Trotter
    return os_obj.ToDict()
476 a8083063 Iustin Pop
477 a8083063 Iustin Pop
  # hooks -----------------------
478 a8083063 Iustin Pop
479 3ecf6786 Iustin Pop
  @staticmethod
480 3ecf6786 Iustin Pop
  def perspective_hooks_runner(params):
481 3ecf6786 Iustin Pop
    """Run hook scripts.
482 3ecf6786 Iustin Pop
483 3ecf6786 Iustin Pop
    """
484 a8083063 Iustin Pop
    hpath, phase, env = params
485 a8083063 Iustin Pop
    hr = backend.HooksRunner()
486 a8083063 Iustin Pop
    return hr.RunHooks(hpath, phase, env)
487 a8083063 Iustin Pop
488 06009e27 Iustin Pop
  # test -----------------------
489 06009e27 Iustin Pop
490 06009e27 Iustin Pop
  @staticmethod
491 06009e27 Iustin Pop
  def perspective_test_delay(params):
492 06009e27 Iustin Pop
    """Run test delay.
493 06009e27 Iustin Pop
494 06009e27 Iustin Pop
    """
495 06009e27 Iustin Pop
    duration = params[0]
496 06009e27 Iustin Pop
    return utils.TestDelay(duration)
497 06009e27 Iustin Pop
498 a8083063 Iustin Pop
499 a8083063 Iustin Pop
def ParseOptions():
500 a8083063 Iustin Pop
  """Parse the command line options.
501 a8083063 Iustin Pop
502 a8083063 Iustin Pop
  Returns:
503 a8083063 Iustin Pop
    (options, args) as from OptionParser.parse_args()
504 a8083063 Iustin Pop
505 a8083063 Iustin Pop
  """
506 a8083063 Iustin Pop
  parser = OptionParser(description="Ganeti node daemon",
507 a8083063 Iustin Pop
                        usage="%prog [-f] [-d]",
508 a8083063 Iustin Pop
                        version="%%prog (ganeti) %s" %
509 a8083063 Iustin Pop
                        constants.RELEASE_VERSION)
510 a8083063 Iustin Pop
511 a8083063 Iustin Pop
  parser.add_option("-f", "--foreground", dest="fork",
512 a8083063 Iustin Pop
                    help="Don't detach from the current terminal",
513 a8083063 Iustin Pop
                    default=True, action="store_false")
514 a8083063 Iustin Pop
  parser.add_option("-d", "--debug", dest="debug",
515 a8083063 Iustin Pop
                    help="Enable some debug messages",
516 a8083063 Iustin Pop
                    default=False, action="store_true")
517 a8083063 Iustin Pop
  options, args = parser.parse_args()
518 a8083063 Iustin Pop
  return options, args
519 a8083063 Iustin Pop
520 a8083063 Iustin Pop
521 a8083063 Iustin Pop
def main():
522 3ecf6786 Iustin Pop
  """Main function for the node daemon.
523 3ecf6786 Iustin Pop
524 3ecf6786 Iustin Pop
  """
525 a8083063 Iustin Pop
  options, args = ParseOptions()
526 f362096f Iustin Pop
  utils.debug = options.debug
527 a8083063 Iustin Pop
  for fname in (constants.SSL_CERT_FILE,):
528 a8083063 Iustin Pop
    if not os.path.isfile(fname):
529 a8083063 Iustin Pop
      print "config %s not there, will not run." % fname
530 a8083063 Iustin Pop
      sys.exit(5)
531 a8083063 Iustin Pop
532 a8083063 Iustin Pop
  try:
533 a8083063 Iustin Pop
    ss = ssconf.SimpleStore()
534 a8083063 Iustin Pop
    port = ss.GetNodeDaemonPort()
535 a8083063 Iustin Pop
    pwdata = ss.GetNodeDaemonPassword()
536 a8083063 Iustin Pop
  except errors.ConfigurationError, err:
537 a8083063 Iustin Pop
    print "Cluster configuration incomplete: '%s'" % str(err)
538 a8083063 Iustin Pop
    sys.exit(5)
539 a8083063 Iustin Pop
540 0214b0c0 Iustin Pop
  # create /var/run/ganeti if not existing, in order to take care of
541 0214b0c0 Iustin Pop
  # tmpfs /var/run
542 0214b0c0 Iustin Pop
  if not os.path.exists(constants.BDEV_CACHE_DIR):
543 0214b0c0 Iustin Pop
    try:
544 0214b0c0 Iustin Pop
      os.mkdir(constants.BDEV_CACHE_DIR, 0755)
545 0214b0c0 Iustin Pop
    except EnvironmentError, err:
546 0214b0c0 Iustin Pop
      if err.errno != errno.EEXIST:
547 0214b0c0 Iustin Pop
        print ("Node setup wrong, cannot create directory %s: %s" %
548 0214b0c0 Iustin Pop
               (constants.BDEV_CACHE_DIR, err))
549 0214b0c0 Iustin Pop
        sys.exit(5)
550 0214b0c0 Iustin Pop
  if not os.path.isdir(constants.BDEV_CACHE_DIR):
551 0214b0c0 Iustin Pop
    print ("Node setup wrong, %s is not a directory" %
552 0214b0c0 Iustin Pop
           constants.BDEV_CACHE_DIR)
553 0214b0c0 Iustin Pop
    sys.exit(5)
554 0214b0c0 Iustin Pop
555 a8083063 Iustin Pop
  # become a daemon
556 a8083063 Iustin Pop
  if options.fork:
557 a8083063 Iustin Pop
    createDaemon()
558 a8083063 Iustin Pop
559 a8083063 Iustin Pop
  logger.SetupLogging(twisted_workaround=True, debug=options.debug,
560 a8083063 Iustin Pop
                      program="ganeti-noded")
561 a8083063 Iustin Pop
562 81010134 Iustin Pop
  httpd = BaseHTTPServer.HTTPServer(('', port), ServerObject)
563 81010134 Iustin Pop
  httpd.serve_forever()
564 a8083063 Iustin Pop
565 a8083063 Iustin Pop
566 a8083063 Iustin Pop
def createDaemon():
567 a8083063 Iustin Pop
  """Detach a process from the controlling terminal and run it in the
568 a8083063 Iustin Pop
  background as a daemon.
569 098c0958 Michael Hanselmann
570 a8083063 Iustin Pop
  """
571 a8083063 Iustin Pop
  UMASK = 077
572 a8083063 Iustin Pop
  WORKDIR = "/"
573 a8083063 Iustin Pop
  # Default maximum for the number of available file descriptors.
574 a8083063 Iustin Pop
  if 'SC_OPEN_MAX' in os.sysconf_names:
575 a8083063 Iustin Pop
    try:
576 a8083063 Iustin Pop
      MAXFD = os.sysconf('SC_OPEN_MAX')
577 a8083063 Iustin Pop
      if MAXFD < 0:
578 a8083063 Iustin Pop
        MAXFD = 1024
579 a8083063 Iustin Pop
    except OSError:
580 a8083063 Iustin Pop
      MAXFD = 1024
581 a8083063 Iustin Pop
  else:
582 a8083063 Iustin Pop
    MAXFD = 1024
583 a8083063 Iustin Pop
  # The standard I/O file descriptors are redirected to /dev/null by default.
584 a8083063 Iustin Pop
  #REDIRECT_TO = getattr(os, "devnull", "/dev/null")
585 a8083063 Iustin Pop
  REDIRECT_TO = constants.LOG_NODESERVER
586 a8083063 Iustin Pop
  try:
587 a8083063 Iustin Pop
    pid = os.fork()
588 a8083063 Iustin Pop
  except OSError, e:
589 3ecf6786 Iustin Pop
    raise Exception("%s [%d]" % (e.strerror, e.errno))
590 3c9a0742 Michael Hanselmann
  if (pid == 0):  # The first child.
591 a8083063 Iustin Pop
    os.setsid()
592 a8083063 Iustin Pop
    try:
593 3c9a0742 Michael Hanselmann
      pid = os.fork() # Fork a second child.
594 a8083063 Iustin Pop
    except OSError, e:
595 3ecf6786 Iustin Pop
      raise Exception("%s [%d]" % (e.strerror, e.errno))
596 3c9a0742 Michael Hanselmann
    if (pid == 0):  # The second child.
597 a8083063 Iustin Pop
      os.chdir(WORKDIR)
598 a8083063 Iustin Pop
      os.umask(UMASK)
599 a8083063 Iustin Pop
    else:
600 a8083063 Iustin Pop
      # exit() or _exit()?  See below.
601 3c9a0742 Michael Hanselmann
      os._exit(0) # Exit parent (the first child) of the second child.
602 a8083063 Iustin Pop
  else:
603 3c9a0742 Michael Hanselmann
    os._exit(0) # Exit parent of the first child.
604 a8083063 Iustin Pop
  maxfd = resource.getrlimit(resource.RLIMIT_NOFILE)[1]
605 a8083063 Iustin Pop
  if (maxfd == resource.RLIM_INFINITY):
606 a8083063 Iustin Pop
    maxfd = MAXFD
607 a8083063 Iustin Pop
608 a8083063 Iustin Pop
  # Iterate through and close all file descriptors.
609 a8083063 Iustin Pop
  for fd in range(0, maxfd):
610 a8083063 Iustin Pop
    try:
611 a8083063 Iustin Pop
      os.close(fd)
612 3c9a0742 Michael Hanselmann
    except OSError: # ERROR, fd wasn't open to begin with (ignored)
613 a8083063 Iustin Pop
      pass
614 b50f022f Iustin Pop
  os.open(REDIRECT_TO, os.O_RDWR|os.O_CREAT|os.O_APPEND, 0600)
615 a8083063 Iustin Pop
  # Duplicate standard input to standard output and standard error.
616 3c9a0742 Michael Hanselmann
  os.dup2(0, 1)     # standard output (1)
617 3c9a0742 Michael Hanselmann
  os.dup2(0, 2)     # standard error (2)
618 a8083063 Iustin Pop
  return(0)
619 a8083063 Iustin Pop
620 a8083063 Iustin Pop
621 3ecf6786 Iustin Pop
if __name__ == '__main__':
622 a8083063 Iustin Pop
  main()