Statistics
| Branch: | Tag: | Revision:

root / daemons / ganeti-noded @ f362096f

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