Statistics
| Branch: | Tag: | Revision:

root / daemons / ganeti-noded @ b50f022f

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