Statistics
| Branch: | Tag: | Revision:

root / daemons / ganeti-noded @ 3ecf6786

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