Statistics
| Branch: | Tag: | Revision:

root / daemons / ganeti-noded @ decd5f45

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