Statistics
| Branch: | Tag: | Revision:

root / daemons / ganeti-noded @ 153d9724

History | View | Annotate | Download (16.1 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 153d9724 Iustin Pop
  def perspective_blockdev_addchildren(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 153d9724 Iustin Pop
    ndevs = [objects.Disk.FromDict(disk_s) for disk_s in ndev_s]
148 153d9724 Iustin Pop
    if bdev is None or ndevs.count(None) > 0:
149 a8083063 Iustin Pop
      raise ValueError("can't unserialize data!")
150 153d9724 Iustin Pop
    return backend.MirrorAddChildren(bdev, ndevs)
151 a8083063 Iustin Pop
152 3ecf6786 Iustin Pop
  @staticmethod
153 153d9724 Iustin Pop
  def perspective_blockdev_removechildren(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 153d9724 Iustin Pop
    ndevs = [objects.Disk.FromDict(disk_s) for disk_s in ndev_s]
163 153d9724 Iustin Pop
    if bdev is None or ndevs.count(None) > 0:
164 a8083063 Iustin Pop
      raise ValueError("can't unserialize data!")
165 153d9724 Iustin Pop
    return backend.MirrorRemoveChildren(bdev, ndevs)
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 007a2f3e Alexander Schreiber
  def perspective_instance_reboot(params):
329 007a2f3e Alexander Schreiber
    """Reboot an instance.
330 007a2f3e Alexander Schreiber
331 007a2f3e Alexander Schreiber
    """
332 007a2f3e Alexander Schreiber
    instance = objects.Instance.FromDict(params[0])
333 007a2f3e Alexander Schreiber
    reboot_type = params[1]
334 007a2f3e Alexander Schreiber
    extra_args = params[2]
335 007a2f3e Alexander Schreiber
    return backend.RebootInstance(instance, reboot_type, extra_args)
336 007a2f3e Alexander Schreiber
337 007a2f3e Alexander Schreiber
  @staticmethod
338 3ecf6786 Iustin Pop
  def perspective_instance_info(params):
339 3ecf6786 Iustin Pop
    """Query instance information.
340 3ecf6786 Iustin Pop
341 3ecf6786 Iustin Pop
    """
342 a8083063 Iustin Pop
    return backend.GetInstanceInfo(params[0])
343 a8083063 Iustin Pop
344 3ecf6786 Iustin Pop
  @staticmethod
345 3ecf6786 Iustin Pop
  def perspective_all_instances_info(params):
346 3ecf6786 Iustin Pop
    """Query information about all instances.
347 3ecf6786 Iustin Pop
348 3ecf6786 Iustin Pop
    """
349 a8083063 Iustin Pop
    return backend.GetAllInstancesInfo()
350 a8083063 Iustin Pop
351 3ecf6786 Iustin Pop
  @staticmethod
352 3ecf6786 Iustin Pop
  def perspective_instance_list(params):
353 3ecf6786 Iustin Pop
    """Query the list of running instances.
354 3ecf6786 Iustin Pop
355 3ecf6786 Iustin Pop
    """
356 a8083063 Iustin Pop
    return backend.GetInstanceList()
357 a8083063 Iustin Pop
358 a8083063 Iustin Pop
  # node --------------------------
359 a8083063 Iustin Pop
360 3ecf6786 Iustin Pop
  @staticmethod
361 16abfbc2 Alexander Schreiber
  def perspective_node_tcp_ping(params):
362 16abfbc2 Alexander Schreiber
    """Do a TcpPing on the remote node.
363 16abfbc2 Alexander Schreiber
364 16abfbc2 Alexander Schreiber
    """
365 16abfbc2 Alexander Schreiber
    return utils.TcpPing(params[0], params[1], params[2],
366 16abfbc2 Alexander Schreiber
                         timeout=params[3], live_port_needed=params[4])
367 16abfbc2 Alexander Schreiber
368 16abfbc2 Alexander Schreiber
  @staticmethod
369 3ecf6786 Iustin Pop
  def perspective_node_info(params):
370 3ecf6786 Iustin Pop
    """Query node information.
371 3ecf6786 Iustin Pop
372 3ecf6786 Iustin Pop
    """
373 a8083063 Iustin Pop
    vgname = params[0]
374 a8083063 Iustin Pop
    return backend.GetNodeInfo(vgname)
375 a8083063 Iustin Pop
376 3ecf6786 Iustin Pop
  @staticmethod
377 3ecf6786 Iustin Pop
  def perspective_node_add(params):
378 3ecf6786 Iustin Pop
    """Complete the registration of this node in the cluster.
379 3ecf6786 Iustin Pop
380 3ecf6786 Iustin Pop
    """
381 a8083063 Iustin Pop
    return backend.AddNode(params[0], params[1], params[2],
382 a8083063 Iustin Pop
                           params[3], params[4], params[5])
383 a8083063 Iustin Pop
384 3ecf6786 Iustin Pop
  @staticmethod
385 3ecf6786 Iustin Pop
  def perspective_node_verify(params):
386 3ecf6786 Iustin Pop
    """Run a verify sequence on this node.
387 3ecf6786 Iustin Pop
388 3ecf6786 Iustin Pop
    """
389 a8083063 Iustin Pop
    return backend.VerifyNode(params[0])
390 a8083063 Iustin Pop
391 3ecf6786 Iustin Pop
  @staticmethod
392 3ecf6786 Iustin Pop
  def perspective_node_start_master(params):
393 3ecf6786 Iustin Pop
    """Promote this node to master status.
394 3ecf6786 Iustin Pop
395 3ecf6786 Iustin Pop
    """
396 a8083063 Iustin Pop
    return backend.StartMaster()
397 a8083063 Iustin Pop
398 3ecf6786 Iustin Pop
  @staticmethod
399 3ecf6786 Iustin Pop
  def perspective_node_stop_master(params):
400 3ecf6786 Iustin Pop
    """Demote this node from master status.
401 3ecf6786 Iustin Pop
402 3ecf6786 Iustin Pop
    """
403 a8083063 Iustin Pop
    return backend.StopMaster()
404 a8083063 Iustin Pop
405 3ecf6786 Iustin Pop
  @staticmethod
406 3ecf6786 Iustin Pop
  def perspective_node_leave_cluster(params):
407 3ecf6786 Iustin Pop
    """Cleanup after leaving a cluster.
408 3ecf6786 Iustin Pop
409 3ecf6786 Iustin Pop
    """
410 a8083063 Iustin Pop
    return backend.LeaveCluster()
411 a8083063 Iustin Pop
412 3ecf6786 Iustin Pop
  @staticmethod
413 3ecf6786 Iustin Pop
  def perspective_node_volumes(params):
414 3ecf6786 Iustin Pop
    """Query the list of all logical volume groups.
415 3ecf6786 Iustin Pop
416 3ecf6786 Iustin Pop
    """
417 dcb93971 Michael Hanselmann
    return backend.NodeVolumes()
418 dcb93971 Michael Hanselmann
419 a8083063 Iustin Pop
  # cluster --------------------------
420 a8083063 Iustin Pop
421 3ecf6786 Iustin Pop
  @staticmethod
422 3ecf6786 Iustin Pop
  def perspective_version(params):
423 3ecf6786 Iustin Pop
    """Query version information.
424 3ecf6786 Iustin Pop
425 3ecf6786 Iustin Pop
    """
426 a8083063 Iustin Pop
    return constants.PROTOCOL_VERSION
427 a8083063 Iustin Pop
428 3ecf6786 Iustin Pop
  @staticmethod
429 3ecf6786 Iustin Pop
  def perspective_upload_file(params):
430 3ecf6786 Iustin Pop
    """Upload a file.
431 3ecf6786 Iustin Pop
432 3ecf6786 Iustin Pop
    Note that the backend implementation imposes strict rules on which
433 3ecf6786 Iustin Pop
    files are accepted.
434 3ecf6786 Iustin Pop
435 3ecf6786 Iustin Pop
    """
436 a8083063 Iustin Pop
    return backend.UploadFile(*params)
437 a8083063 Iustin Pop
438 a8083063 Iustin Pop
439 a8083063 Iustin Pop
  # os -----------------------
440 a8083063 Iustin Pop
441 3ecf6786 Iustin Pop
  @staticmethod
442 3ecf6786 Iustin Pop
  def perspective_os_diagnose(params):
443 3ecf6786 Iustin Pop
    """Query detailed information about existing OSes.
444 3ecf6786 Iustin Pop
445 3ecf6786 Iustin Pop
    """
446 a8083063 Iustin Pop
    os_list = backend.DiagnoseOS()
447 a8083063 Iustin Pop
    if not os_list:
448 a8083063 Iustin Pop
      # this catches also return values of 'False',
449 a8083063 Iustin Pop
      # for which we can't iterate over
450 a8083063 Iustin Pop
      return os_list
451 a8083063 Iustin Pop
    result = []
452 a8083063 Iustin Pop
    for data in os_list:
453 a8083063 Iustin Pop
      if isinstance(data, objects.OS):
454 319856a9 Michael Hanselmann
        result.append(data.ToDict())
455 a8083063 Iustin Pop
      elif isinstance(data, errors.InvalidOS):
456 a8083063 Iustin Pop
        result.append(data.args)
457 a8083063 Iustin Pop
      else:
458 3ecf6786 Iustin Pop
        raise errors.ProgrammerError("Invalid result from backend.DiagnoseOS"
459 3ecf6786 Iustin Pop
                                     " (class %s, %s)" %
460 3ecf6786 Iustin Pop
                                     (str(data.__class__), data))
461 a8083063 Iustin Pop
462 a8083063 Iustin Pop
    return result
463 a8083063 Iustin Pop
464 3ecf6786 Iustin Pop
  @staticmethod
465 3ecf6786 Iustin Pop
  def perspective_os_get(params):
466 3ecf6786 Iustin Pop
    """Query information about a given OS.
467 3ecf6786 Iustin Pop
468 3ecf6786 Iustin Pop
    """
469 a8083063 Iustin Pop
    name = params[0]
470 a8083063 Iustin Pop
    try:
471 319856a9 Michael Hanselmann
      os_obj = backend.OSFromDisk(name).ToDict()
472 a8083063 Iustin Pop
    except errors.InvalidOS, err:
473 3ecf6786 Iustin Pop
      os_obj = err.args
474 3ecf6786 Iustin Pop
    return os_obj
475 a8083063 Iustin Pop
476 a8083063 Iustin Pop
  # hooks -----------------------
477 a8083063 Iustin Pop
478 3ecf6786 Iustin Pop
  @staticmethod
479 3ecf6786 Iustin Pop
  def perspective_hooks_runner(params):
480 3ecf6786 Iustin Pop
    """Run hook scripts.
481 3ecf6786 Iustin Pop
482 3ecf6786 Iustin Pop
    """
483 a8083063 Iustin Pop
    hpath, phase, env = params
484 a8083063 Iustin Pop
    hr = backend.HooksRunner()
485 a8083063 Iustin Pop
    return hr.RunHooks(hpath, phase, env)
486 a8083063 Iustin Pop
487 a8083063 Iustin Pop
488 a8083063 Iustin Pop
class MyRealm:
489 3ecf6786 Iustin Pop
  """Simple realm that forwards all requests to a ServerObject.
490 3ecf6786 Iustin Pop
491 3ecf6786 Iustin Pop
  """
492 a8083063 Iustin Pop
  __implements__ = portal.IRealm
493 3ecf6786 Iustin Pop
494 a8083063 Iustin Pop
  def requestAvatar(self, avatarId, mind, *interfaces):
495 3ecf6786 Iustin Pop
    """Return an avatar based on our ServerObject class.
496 3ecf6786 Iustin Pop
497 3ecf6786 Iustin Pop
    """
498 a8083063 Iustin Pop
    if pb.IPerspective not in interfaces:
499 a8083063 Iustin Pop
      raise NotImplementedError
500 a8083063 Iustin Pop
    return pb.IPerspective, ServerObject(avatarId), lambda:None
501 a8083063 Iustin Pop
502 a8083063 Iustin Pop
503 a8083063 Iustin Pop
def ParseOptions():
504 a8083063 Iustin Pop
  """Parse the command line options.
505 a8083063 Iustin Pop
506 a8083063 Iustin Pop
  Returns:
507 a8083063 Iustin Pop
    (options, args) as from OptionParser.parse_args()
508 a8083063 Iustin Pop
509 a8083063 Iustin Pop
  """
510 a8083063 Iustin Pop
  parser = OptionParser(description="Ganeti node daemon",
511 a8083063 Iustin Pop
                        usage="%prog [-f] [-d]",
512 a8083063 Iustin Pop
                        version="%%prog (ganeti) %s" %
513 a8083063 Iustin Pop
                        constants.RELEASE_VERSION)
514 a8083063 Iustin Pop
515 a8083063 Iustin Pop
  parser.add_option("-f", "--foreground", dest="fork",
516 a8083063 Iustin Pop
                    help="Don't detach from the current terminal",
517 a8083063 Iustin Pop
                    default=True, action="store_false")
518 a8083063 Iustin Pop
  parser.add_option("-d", "--debug", dest="debug",
519 a8083063 Iustin Pop
                    help="Enable some debug messages",
520 a8083063 Iustin Pop
                    default=False, action="store_true")
521 a8083063 Iustin Pop
  options, args = parser.parse_args()
522 a8083063 Iustin Pop
  return options, args
523 a8083063 Iustin Pop
524 a8083063 Iustin Pop
525 a8083063 Iustin Pop
def main():
526 3ecf6786 Iustin Pop
  """Main function for the node daemon.
527 3ecf6786 Iustin Pop
528 3ecf6786 Iustin Pop
  """
529 a8083063 Iustin Pop
  options, args = ParseOptions()
530 a8083063 Iustin Pop
  for fname in (constants.SSL_CERT_FILE,):
531 a8083063 Iustin Pop
    if not os.path.isfile(fname):
532 a8083063 Iustin Pop
      print "config %s not there, will not run." % fname
533 a8083063 Iustin Pop
      sys.exit(5)
534 a8083063 Iustin Pop
535 a8083063 Iustin Pop
  try:
536 a8083063 Iustin Pop
    ss = ssconf.SimpleStore()
537 a8083063 Iustin Pop
    port = ss.GetNodeDaemonPort()
538 a8083063 Iustin Pop
    pwdata = ss.GetNodeDaemonPassword()
539 a8083063 Iustin Pop
  except errors.ConfigurationError, err:
540 a8083063 Iustin Pop
    print "Cluster configuration incomplete: '%s'" % str(err)
541 a8083063 Iustin Pop
    sys.exit(5)
542 a8083063 Iustin Pop
543 a8083063 Iustin Pop
  # become a daemon
544 a8083063 Iustin Pop
  if options.fork:
545 a8083063 Iustin Pop
    createDaemon()
546 a8083063 Iustin Pop
547 a8083063 Iustin Pop
  logger.SetupLogging(twisted_workaround=True, debug=options.debug,
548 a8083063 Iustin Pop
                      program="ganeti-noded")
549 a8083063 Iustin Pop
550 a8083063 Iustin Pop
  p = portal.Portal(MyRealm())
551 a8083063 Iustin Pop
  p.registerChecker(
552 a8083063 Iustin Pop
    checkers.InMemoryUsernamePasswordDatabaseDontUse(master_node=pwdata))
553 a8083063 Iustin Pop
  reactor.listenSSL(port, pb.PBServerFactory(p), ServerContextFactory())
554 a8083063 Iustin Pop
  reactor.run()
555 a8083063 Iustin Pop
556 a8083063 Iustin Pop
557 a8083063 Iustin Pop
def createDaemon():
558 a8083063 Iustin Pop
  """Detach a process from the controlling terminal and run it in the
559 a8083063 Iustin Pop
  background as a daemon.
560 098c0958 Michael Hanselmann
561 a8083063 Iustin Pop
  """
562 a8083063 Iustin Pop
  UMASK = 077
563 a8083063 Iustin Pop
  WORKDIR = "/"
564 a8083063 Iustin Pop
  # Default maximum for the number of available file descriptors.
565 a8083063 Iustin Pop
  if 'SC_OPEN_MAX' in os.sysconf_names:
566 a8083063 Iustin Pop
    try:
567 a8083063 Iustin Pop
      MAXFD = os.sysconf('SC_OPEN_MAX')
568 a8083063 Iustin Pop
      if MAXFD < 0:
569 a8083063 Iustin Pop
        MAXFD = 1024
570 a8083063 Iustin Pop
    except OSError:
571 a8083063 Iustin Pop
      MAXFD = 1024
572 a8083063 Iustin Pop
  else:
573 a8083063 Iustin Pop
    MAXFD = 1024
574 a8083063 Iustin Pop
  # The standard I/O file descriptors are redirected to /dev/null by default.
575 a8083063 Iustin Pop
  #REDIRECT_TO = getattr(os, "devnull", "/dev/null")
576 a8083063 Iustin Pop
  REDIRECT_TO = constants.LOG_NODESERVER
577 a8083063 Iustin Pop
  try:
578 a8083063 Iustin Pop
    pid = os.fork()
579 a8083063 Iustin Pop
  except OSError, e:
580 3ecf6786 Iustin Pop
    raise Exception("%s [%d]" % (e.strerror, e.errno))
581 3c9a0742 Michael Hanselmann
  if (pid == 0):  # The first child.
582 a8083063 Iustin Pop
    os.setsid()
583 a8083063 Iustin Pop
    try:
584 3c9a0742 Michael Hanselmann
      pid = os.fork() # Fork a second child.
585 a8083063 Iustin Pop
    except OSError, e:
586 3ecf6786 Iustin Pop
      raise Exception("%s [%d]" % (e.strerror, e.errno))
587 3c9a0742 Michael Hanselmann
    if (pid == 0):  # The second child.
588 a8083063 Iustin Pop
      os.chdir(WORKDIR)
589 a8083063 Iustin Pop
      os.umask(UMASK)
590 a8083063 Iustin Pop
    else:
591 a8083063 Iustin Pop
      # exit() or _exit()?  See below.
592 3c9a0742 Michael Hanselmann
      os._exit(0) # Exit parent (the first child) of the second child.
593 a8083063 Iustin Pop
  else:
594 3c9a0742 Michael Hanselmann
    os._exit(0) # Exit parent of the first child.
595 a8083063 Iustin Pop
  maxfd = resource.getrlimit(resource.RLIMIT_NOFILE)[1]
596 a8083063 Iustin Pop
  if (maxfd == resource.RLIM_INFINITY):
597 a8083063 Iustin Pop
    maxfd = MAXFD
598 a8083063 Iustin Pop
599 a8083063 Iustin Pop
  # Iterate through and close all file descriptors.
600 a8083063 Iustin Pop
  for fd in range(0, maxfd):
601 a8083063 Iustin Pop
    try:
602 a8083063 Iustin Pop
      os.close(fd)
603 3c9a0742 Michael Hanselmann
    except OSError: # ERROR, fd wasn't open to begin with (ignored)
604 a8083063 Iustin Pop
      pass
605 b50f022f Iustin Pop
  os.open(REDIRECT_TO, os.O_RDWR|os.O_CREAT|os.O_APPEND, 0600)
606 a8083063 Iustin Pop
  # Duplicate standard input to standard output and standard error.
607 3c9a0742 Michael Hanselmann
  os.dup2(0, 1)     # standard output (1)
608 3c9a0742 Michael Hanselmann
  os.dup2(0, 2)     # standard error (2)
609 a8083063 Iustin Pop
  return(0)
610 a8083063 Iustin Pop
611 a8083063 Iustin Pop
612 3ecf6786 Iustin Pop
if __name__ == '__main__':
613 a8083063 Iustin Pop
  main()