Revision a8083063

b/COPYING
1
		    GNU GENERAL PUBLIC LICENSE
2
		       Version 2, June 1991
3

  
4
 Copyright (C) 1989, 1991 Free Software Foundation, Inc.
5
     51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
6
 Everyone is permitted to copy and distribute verbatim copies
7
 of this license document, but changing it is not allowed.
8

  
9
			    Preamble
10

  
11
  The licenses for most software are designed to take away your
12
freedom to share and change it.  By contrast, the GNU General Public
13
License is intended to guarantee your freedom to share and change free
14
software--to make sure the software is free for all its users.  This
15
General Public License applies to most of the Free Software
16
Foundation's software and to any other program whose authors commit to
17
using it.  (Some other Free Software Foundation software is covered by
18
the GNU Library General Public License instead.)  You can apply it to
19
your programs, too.
20

  
21
  When we speak of free software, we are referring to freedom, not
22
price.  Our General Public Licenses are designed to make sure that you
23
have the freedom to distribute copies of free software (and charge for
24
this service if you wish), that you receive source code or can get it
25
if you want it, that you can change the software or use pieces of it
26
in new free programs; and that you know you can do these things.
27

  
28
  To protect your rights, we need to make restrictions that forbid
29
anyone to deny you these rights or to ask you to surrender the rights.
30
These restrictions translate to certain responsibilities for you if you
31
distribute copies of the software, or if you modify it.
32

  
33
  For example, if you distribute copies of such a program, whether
34
gratis or for a fee, you must give the recipients all the rights that
35
you have.  You must make sure that they, too, receive or can get the
36
source code.  And you must show them these terms so they know their
37
rights.
38

  
39
  We protect your rights with two steps: (1) copyright the software, and
40
(2) offer you this license which gives you legal permission to copy,
41
distribute and/or modify the software.
42

  
43
  Also, for each author's protection and ours, we want to make certain
44
that everyone understands that there is no warranty for this free
45
software.  If the software is modified by someone else and passed on, we
46
want its recipients to know that what they have is not the original, so
47
that any problems introduced by others will not reflect on the original
48
authors' reputations.
49

  
50
  Finally, any free program is threatened constantly by software
51
patents.  We wish to avoid the danger that redistributors of a free
52
program will individually obtain patent licenses, in effect making the
53
program proprietary.  To prevent this, we have made it clear that any
54
patent must be licensed for everyone's free use or not licensed at all.
55

  
56
  The precise terms and conditions for copying, distribution and
57
modification follow.
58

59
		    GNU GENERAL PUBLIC LICENSE
60
   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
61

  
62
  0. This License applies to any program or other work which contains
63
a notice placed by the copyright holder saying it may be distributed
64
under the terms of this General Public License.  The "Program", below,
65
refers to any such program or work, and a "work based on the Program"
66
means either the Program or any derivative work under copyright law:
67
that is to say, a work containing the Program or a portion of it,
68
either verbatim or with modifications and/or translated into another
69
language.  (Hereinafter, translation is included without limitation in
70
the term "modification".)  Each licensee is addressed as "you".
71

  
72
Activities other than copying, distribution and modification are not
73
covered by this License; they are outside its scope.  The act of
74
running the Program is not restricted, and the output from the Program
75
is covered only if its contents constitute a work based on the
76
Program (independent of having been made by running the Program).
77
Whether that is true depends on what the Program does.
78

  
79
  1. You may copy and distribute verbatim copies of the Program's
80
source code as you receive it, in any medium, provided that you
81
conspicuously and appropriately publish on each copy an appropriate
82
copyright notice and disclaimer of warranty; keep intact all the
83
notices that refer to this License and to the absence of any warranty;
84
and give any other recipients of the Program a copy of this License
85
along with the Program.
86

  
87
You may charge a fee for the physical act of transferring a copy, and
88
you may at your option offer warranty protection in exchange for a fee.
89

  
90
  2. You may modify your copy or copies of the Program or any portion
91
of it, thus forming a work based on the Program, and copy and
92
distribute such modifications or work under the terms of Section 1
93
above, provided that you also meet all of these conditions:
94

  
95
    a) You must cause the modified files to carry prominent notices
96
    stating that you changed the files and the date of any change.
97

  
98
    b) You must cause any work that you distribute or publish, that in
99
    whole or in part contains or is derived from the Program or any
100
    part thereof, to be licensed as a whole at no charge to all third
101
    parties under the terms of this License.
102

  
103
    c) If the modified program normally reads commands interactively
104
    when run, you must cause it, when started running for such
105
    interactive use in the most ordinary way, to print or display an
106
    announcement including an appropriate copyright notice and a
107
    notice that there is no warranty (or else, saying that you provide
108
    a warranty) and that users may redistribute the program under
109
    these conditions, and telling the user how to view a copy of this
110
    License.  (Exception: if the Program itself is interactive but
111
    does not normally print such an announcement, your work based on
112
    the Program is not required to print an announcement.)
113

114
These requirements apply to the modified work as a whole.  If
115
identifiable sections of that work are not derived from the Program,
116
and can be reasonably considered independent and separate works in
117
themselves, then this License, and its terms, do not apply to those
118
sections when you distribute them as separate works.  But when you
119
distribute the same sections as part of a whole which is a work based
120
on the Program, the distribution of the whole must be on the terms of
121
this License, whose permissions for other licensees extend to the
122
entire whole, and thus to each and every part regardless of who wrote it.
123

  
124
Thus, it is not the intent of this section to claim rights or contest
125
your rights to work written entirely by you; rather, the intent is to
126
exercise the right to control the distribution of derivative or
127
collective works based on the Program.
128

  
129
In addition, mere aggregation of another work not based on the Program
130
with the Program (or with a work based on the Program) on a volume of
131
a storage or distribution medium does not bring the other work under
132
the scope of this License.
133

  
134
  3. You may copy and distribute the Program (or a work based on it,
135
under Section 2) in object code or executable form under the terms of
136
Sections 1 and 2 above provided that you also do one of the following:
137

  
138
    a) Accompany it with the complete corresponding machine-readable
139
    source code, which must be distributed under the terms of Sections
140
    1 and 2 above on a medium customarily used for software interchange; or,
141

  
142
    b) Accompany it with a written offer, valid for at least three
143
    years, to give any third party, for a charge no more than your
144
    cost of physically performing source distribution, a complete
145
    machine-readable copy of the corresponding source code, to be
146
    distributed under the terms of Sections 1 and 2 above on a medium
147
    customarily used for software interchange; or,
148

  
149
    c) Accompany it with the information you received as to the offer
150
    to distribute corresponding source code.  (This alternative is
151
    allowed only for noncommercial distribution and only if you
152
    received the program in object code or executable form with such
153
    an offer, in accord with Subsection b above.)
154

  
155
The source code for a work means the preferred form of the work for
156
making modifications to it.  For an executable work, complete source
157
code means all the source code for all modules it contains, plus any
158
associated interface definition files, plus the scripts used to
159
control compilation and installation of the executable.  However, as a
160
special exception, the source code distributed need not include
161
anything that is normally distributed (in either source or binary
162
form) with the major components (compiler, kernel, and so on) of the
163
operating system on which the executable runs, unless that component
164
itself accompanies the executable.
165

  
166
If distribution of executable or object code is made by offering
167
access to copy from a designated place, then offering equivalent
168
access to copy the source code from the same place counts as
169
distribution of the source code, even though third parties are not
170
compelled to copy the source along with the object code.
171

172
  4. You may not copy, modify, sublicense, or distribute the Program
173
except as expressly provided under this License.  Any attempt
174
otherwise to copy, modify, sublicense or distribute the Program is
175
void, and will automatically terminate your rights under this License.
176
However, parties who have received copies, or rights, from you under
177
this License will not have their licenses terminated so long as such
178
parties remain in full compliance.
179

  
180
  5. You are not required to accept this License, since you have not
181
signed it.  However, nothing else grants you permission to modify or
182
distribute the Program or its derivative works.  These actions are
183
prohibited by law if you do not accept this License.  Therefore, by
184
modifying or distributing the Program (or any work based on the
185
Program), you indicate your acceptance of this License to do so, and
186
all its terms and conditions for copying, distributing or modifying
187
the Program or works based on it.
188

  
189
  6. Each time you redistribute the Program (or any work based on the
190
Program), the recipient automatically receives a license from the
191
original licensor to copy, distribute or modify the Program subject to
192
these terms and conditions.  You may not impose any further
193
restrictions on the recipients' exercise of the rights granted herein.
194
You are not responsible for enforcing compliance by third parties to
195
this License.
196

  
197
  7. If, as a consequence of a court judgment or allegation of patent
198
infringement or for any other reason (not limited to patent issues),
199
conditions are imposed on you (whether by court order, agreement or
200
otherwise) that contradict the conditions of this License, they do not
201
excuse you from the conditions of this License.  If you cannot
202
distribute so as to satisfy simultaneously your obligations under this
203
License and any other pertinent obligations, then as a consequence you
204
may not distribute the Program at all.  For example, if a patent
205
license would not permit royalty-free redistribution of the Program by
206
all those who receive copies directly or indirectly through you, then
207
the only way you could satisfy both it and this License would be to
208
refrain entirely from distribution of the Program.
209

  
210
If any portion of this section is held invalid or unenforceable under
211
any particular circumstance, the balance of the section is intended to
212
apply and the section as a whole is intended to apply in other
213
circumstances.
214

  
215
It is not the purpose of this section to induce you to infringe any
216
patents or other property right claims or to contest validity of any
217
such claims; this section has the sole purpose of protecting the
218
integrity of the free software distribution system, which is
219
implemented by public license practices.  Many people have made
220
generous contributions to the wide range of software distributed
221
through that system in reliance on consistent application of that
222
system; it is up to the author/donor to decide if he or she is willing
223
to distribute software through any other system and a licensee cannot
224
impose that choice.
225

  
226
This section is intended to make thoroughly clear what is believed to
227
be a consequence of the rest of this License.
228

229
  8. If the distribution and/or use of the Program is restricted in
230
certain countries either by patents or by copyrighted interfaces, the
231
original copyright holder who places the Program under this License
232
may add an explicit geographical distribution limitation excluding
233
those countries, so that distribution is permitted only in or among
234
countries not thus excluded.  In such case, this License incorporates
235
the limitation as if written in the body of this License.
236

  
237
  9. The Free Software Foundation may publish revised and/or new versions
238
of the General Public License from time to time.  Such new versions will
239
be similar in spirit to the present version, but may differ in detail to
240
address new problems or concerns.
241

  
242
Each version is given a distinguishing version number.  If the Program
243
specifies a version number of this License which applies to it and "any
244
later version", you have the option of following the terms and conditions
245
either of that version or of any later version published by the Free
246
Software Foundation.  If the Program does not specify a version number of
247
this License, you may choose any version ever published by the Free Software
248
Foundation.
249

  
250
  10. If you wish to incorporate parts of the Program into other free
251
programs whose distribution conditions are different, write to the author
252
to ask for permission.  For software which is copyrighted by the Free
253
Software Foundation, write to the Free Software Foundation; we sometimes
254
make exceptions for this.  Our decision will be guided by the two goals
255
of preserving the free status of all derivatives of our free software and
256
of promoting the sharing and reuse of software generally.
257

  
258
			    NO WARRANTY
259

  
260
  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
261
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
262
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
263
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
264
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
265
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
266
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
267
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
268
REPAIR OR CORRECTION.
269

  
270
  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
271
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
272
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
273
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
274
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
275
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
276
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
277
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
278
POSSIBILITY OF SUCH DAMAGES.
279

  
280
		     END OF TERMS AND CONDITIONS
281

282
	    How to Apply These Terms to Your New Programs
283

  
284
  If you develop a new program, and you want it to be of the greatest
285
possible use to the public, the best way to achieve this is to make it
286
free software which everyone can redistribute and change under these terms.
287

  
288
  To do so, attach the following notices to the program.  It is safest
289
to attach them to the start of each source file to most effectively
290
convey the exclusion of warranty; and each file should have at least
291
the "copyright" line and a pointer to where the full notice is found.
292

  
293
    <one line to give the program's name and a brief idea of what it does.>
294
    Copyright (C) <year>  <name of author>
295

  
296
    This program is free software; you can redistribute it and/or modify
297
    it under the terms of the GNU General Public License as published by
298
    the Free Software Foundation; either version 2 of the License, or
299
    (at your option) any later version.
300

  
301
    This program is distributed in the hope that it will be useful,
302
    but WITHOUT ANY WARRANTY; without even the implied warranty of
303
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
304
    GNU General Public License for more details.
305

  
306
    You should have received a copy of the GNU General Public License
307
    along with this program; if not, write to the Free Software
308
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
309

  
310

  
311
Also add information on how to contact you by electronic and paper mail.
312

  
313
If the program is interactive, make it output a short notice like this
314
when it starts in an interactive mode:
315

  
316
    Gnomovision version 69, Copyright (C) year  name of author
317
    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
318
    This is free software, and you are welcome to redistribute it
319
    under certain conditions; type `show c' for details.
320

  
321
The hypothetical commands `show w' and `show c' should show the appropriate
322
parts of the General Public License.  Of course, the commands you use may
323
be called something other than `show w' and `show c'; they could even be
324
mouse-clicks or menu items--whatever suits your program.
325

  
326
You should also get your employer (if you work as a programmer) or your
327
school, if any, to sign a "copyright disclaimer" for the program, if
328
necessary.  Here is a sample; alter the names:
329

  
330
  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
331
  `Gnomovision' (which makes passes at compilers) written by James Hacker.
332

  
333
  <signature of Ty Coon>, 1 April 1989
334
  Ty Coon, President of Vice
335

  
336
This General Public License does not permit incorporating your program into
337
proprietary programs.  If your program is a subroutine library, you may
338
consider it more useful to permit linking proprietary applications with the
339
library.  If this is what you want to do, use the GNU Library General
340
Public License instead of this License.
b/INSTALL
1
Installation of the software
2
============================
3

  
4
Before installing, please verify that you have the following programs:
5
  - lvm 2
6
  - ssh
7
  - fping
8
  - python twisted library (the core is enough)
9
  - python openssl bindings
10

  
11
To install, simply do ./configure && make && make install
12

  
13
This will install the software under /usr/local. You then need to copy
14
ganeti.init to /etc/init.d and integrate it into your boot sequence
15
(``chkconfig``, ``update-rc.d``, etc.).
16

  
17
Cluster initialisation
18
======================
19

  
20
Before initialising the cluster, on each node you need to create the following
21
directories:
22

  
23
  - /etc/ganeti
24
  - /var/log/ganeti
25
  - /var/lib/ganeti
26
  - /srv/ganeti and /srv/ganeti/os
27

  
28
After this, use ``gnt-cluster init``.
b/Makefile.am
1
# standard automake rules
2

  
3
SUBDIRS = man lib scripts daemons docs testing tools
4
EXTRA_DIST = ganeti.initd
5

  
6
# custom rules
7
depgraph: depgraph.png
8

  
9
depgraph.png: depgraph.dot
10
	dot -Tpng -o $@ $<
11

  
12
depgraph.ps: depgraph.dot
13
	dot -Tps -o $@ $<
14

  
15
depgraph.dot: ganeti/*.py
16
	pylint.python2.4 --indent-string '  ' --rcfile=/dev/null --reports y --int-import-graph $@ --persistent n ganeti >/dev/null
b/README
1
Ganeti 1.2
2
==========
3

  
4
For installation instructions, read the INSTALL file.
5

  
6
For a brief introduction, read the ganeti(7) manpage and the other pages
7
it suggests.
b/configure.ac
1
#                                               -*- Autoconf -*-
2
# Process this file with autoconf to produce a configure script.
3

  
4
AC_PREREQ(2.59)
5
AC_INIT(ganeti, 1.2a, ganeti@googlegroups.com)
6
AM_INIT_AUTOMAKE(foreign)
7

  
8
# Checks for programs.
9
AC_PROG_INSTALL
10

  
11
# Checks for python
12
AM_PATH_PYTHON(2.4)
13

  
14
# Checks for libraries.
15

  
16
# Checks for header files.
17

  
18
# Checks for typedefs, structures, and compiler characteristics.
19

  
20
# Checks for library functions.
21

  
22
AC_CONFIG_FILES([Makefile man/Makefile docs/Makefile 
23
		testing/Makefile tools/Makefile
24
		lib/Makefile scripts/Makefile daemons/Makefile])
25
AC_OUTPUT
b/daemons/Makefile.am
1
dist_sbin_SCRIPTS = ganeti-noded ganeti-watcher
b/daemons/ganeti-noded
1
#!/usr/bin/python
2
#
3

  
4
# Copyright (C) 2006, 2007 Google Inc.
5
#
6
# This program is free software; you can redistribute it and/or modify
7
# it under the terms of the GNU General Public License as published by
8
# the Free Software Foundation; either version 2 of the License, or
9
# (at your option) any later version.
10
#
11
# This program is distributed in the hope that it will be useful, but
12
# WITHOUT ANY WARRANTY; without even the implied warranty of
13
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14
# General Public License for more details.
15
#
16
# You should have received a copy of the GNU General Public License
17
# along with this program; if not, write to the Free Software
18
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19
# 02110-1301, USA.
20

  
21

  
22
"""Ganeti node daemon"""
23

  
24
import os
25
import sys
26
import resource
27
import traceback
28

  
29
from optparse import OptionParser
30

  
31

  
32
from ganeti import backend
33
from ganeti import logger
34
from ganeti import constants
35
from ganeti import objects
36
from ganeti import errors
37
from ganeti import ssconf
38

  
39
from twisted.spread import pb
40
from twisted.internet import reactor
41
from twisted.cred import checkers, portal
42
from OpenSSL import SSL
43

  
44

  
45
class ServerContextFactory:
46
  def getContext(self):
47
    ctx = SSL.Context(SSL.TLSv1_METHOD)
48
    ctx.use_certificate_file(constants.SSL_CERT_FILE)
49
    ctx.use_privatekey_file(constants.SSL_CERT_FILE)
50
    return ctx
51

  
52
class ServerObject(pb.Avatar):
53
  def __init__(self, name):
54
    self.name = name
55

  
56
  def perspectiveMessageReceived(self, broker, message, args, kw):
57
    """This method is called when a network message is received.
58

  
59
    I will call::
60

  
61
      |  self.perspective_%(message)s(*broker.unserialize(args),
62
      |                               **broker.unserialize(kw))
63

  
64
    to handle the method; subclasses of Avatar are expected to
65
    implement methods of this naming convention.
66
    """
67

  
68
    args = broker.unserialize(args, self)
69
    kw = broker.unserialize(kw, self)
70
    method = getattr(self, "perspective_%s" % message)
71
    tb = None
72
    state = None
73
    try:
74
      state = method(*args, **kw)
75
    except:
76
      tb = traceback.format_exc()
77

  
78
    return broker.serialize((tb, state), self, method, args, kw)
79

  
80
  # the new block devices  --------------------------
81

  
82
  def perspective_blockdev_create(self,params):
83
    bdev_s, size, on_primary = params
84
    bdev = objects.ConfigObject.Loads(bdev_s)
85
    if bdev is None:
86
      raise ValueError("can't unserialize data!")
87
    return backend.CreateBlockDevice(bdev, size, on_primary)
88

  
89

  
90
  def perspective_blockdev_remove(self,params):
91
    bdev_s = params[0]
92
    bdev = objects.ConfigObject.Loads(bdev_s)
93
    return backend.RemoveBlockDevice(bdev)
94

  
95

  
96
  def perspective_blockdev_assemble(self,params):
97
    bdev_s, on_primary = params
98
    bdev = objects.ConfigObject.Loads(bdev_s)
99
    if bdev is None:
100
      raise ValueError("can't unserialize data!")
101
    return backend.AssembleBlockDevice(bdev, on_primary)
102

  
103

  
104
  def perspective_blockdev_shutdown(self,params):
105
    bdev_s = params[0]
106
    bdev = objects.ConfigObject.Loads(bdev_s)
107
    if bdev is None:
108
      raise ValueError("can't unserialize data!")
109
    return backend.ShutdownBlockDevice(bdev)
110

  
111

  
112
  def perspective_blockdev_addchild(self,params):
113
    bdev_s, ndev_s = params
114
    bdev = objects.ConfigObject.Loads(bdev_s)
115
    ndev = objects.ConfigObject.Loads(ndev_s)
116
    if bdev is None or ndev is None:
117
      raise ValueError("can't unserialize data!")
118
    return backend.MirrorAddChild(bdev, ndev)
119

  
120

  
121
  def perspective_blockdev_removechild(self,params):
122
    bdev_s, ndev_s = params
123
    bdev = objects.ConfigObject.Loads(bdev_s)
124
    ndev = objects.ConfigObject.Loads(ndev_s)
125
    if bdev is None or ndev is None:
126
      raise ValueError("can't unserialize data!")
127
    return backend.MirrorRemoveChild(bdev, ndev)
128

  
129
  def perspective_blockdev_getmirrorstatus(self, params):
130
    disks = [objects.ConfigObject.Loads(dsk_s)
131
            for dsk_s in params]
132
    return backend.GetMirrorStatus(disks)
133

  
134
  def perspective_blockdev_find(self, params):
135
    disk = objects.ConfigObject.Loads(params[0])
136
    return backend.FindBlockDevice(disk)
137

  
138
  def perspective_blockdev_snapshot(self,params):
139
    cfbd = objects.ConfigObject.Loads(params[0])
140
    return backend.SnapshotBlockDevice(cfbd)
141

  
142
  # export/import  --------------------------
143

  
144
  def perspective_snapshot_export(self,params):
145
    disk = objects.ConfigObject.Loads(params[0])
146
    dest_node = params[1]
147
    instance = objects.ConfigObject.Loads(params[2])
148
    return backend.ExportSnapshot(disk,dest_node,instance)
149

  
150
  def perspective_finalize_export(self,params):
151
    instance = objects.ConfigObject.Loads(params[0])
152
    snap_disks = [objects.ConfigObject.Loads(str_data)
153
                  for str_data in params[1]]
154
    return backend.FinalizeExport(instance, snap_disks)
155

  
156
  def perspective_export_info(self,params):
157
    dir = params[0]
158
    einfo = backend.ExportInfo(dir)
159
    if einfo is None:
160
      return einfo
161
    return einfo.Dumps()
162

  
163
  def perspective_export_list(self, params):
164
    return backend.ListExports()
165

  
166
  def perspective_export_remove(self, params):
167
    export = params[0]
168
    return backend.RemoveExport(export)
169

  
170
  # volume  --------------------------
171

  
172
  def perspective_volume_list(self,params):
173
    vgname = params[0]
174
    return backend.GetVolumeList(vgname)
175

  
176
  def perspective_vg_list(self,params):
177
    return backend.ListVolumeGroups()
178

  
179
  # bridge  --------------------------
180

  
181
  def perspective_bridges_exist(self,params):
182
    bridges_list = params[0]
183
    return backend.BridgesExist(bridges_list)
184

  
185
  # instance  --------------------------
186

  
187
  def perspective_instance_os_add(self,params):
188
    inst_s, os_disk, swap_disk = params
189
    inst = objects.ConfigObject.Loads(inst_s)
190
    return backend.AddOSToInstance(inst, os_disk, swap_disk)
191

  
192
  def perspective_instance_os_import(self, params):
193
    inst_s, os_disk, swap_disk, src_node, src_image = params
194
    inst = objects.ConfigObject.Loads(inst_s)
195
    return backend.ImportOSIntoInstance(inst, os_disk, swap_disk,
196
                                        src_node, src_image)
197

  
198
  def perspective_instance_shutdown(self,params):
199
    instance = objects.ConfigObject.Loads(params[0])
200
    return backend.ShutdownInstance(instance)
201

  
202
  def perspective_instance_start(self,params):
203
    instance = objects.ConfigObject.Loads(params[0])
204
    extra_args = params[1]
205
    return backend.StartInstance(instance, extra_args)
206

  
207
  def perspective_instance_info(self,params):
208
    return backend.GetInstanceInfo(params[0])
209

  
210
  def perspective_all_instances_info(self,params):
211
    return backend.GetAllInstancesInfo()
212

  
213
  def perspective_instance_list(self,params):
214
    return backend.GetInstanceList()
215

  
216
  # node --------------------------
217

  
218
  def perspective_node_info(self,params):
219
    vgname = params[0]
220
    return backend.GetNodeInfo(vgname)
221

  
222
  def perspective_node_add(self,params):
223
    return backend.AddNode(params[0], params[1], params[2],
224
                           params[3], params[4], params[5])
225

  
226
  def perspective_node_verify(self,params):
227
    return backend.VerifyNode(params[0])
228

  
229
  def perspective_node_start_master(self, params):
230
    return backend.StartMaster()
231

  
232
  def perspective_node_stop_master(self, params):
233
    return backend.StopMaster()
234

  
235
  def perspective_node_leave_cluster(self, params):
236
    return backend.LeaveCluster()
237

  
238
  # cluster --------------------------
239

  
240
  def perspective_version(self,params):
241
    return constants.PROTOCOL_VERSION
242

  
243
  def perspective_configfile_list(self,params):
244
    return backend.ListConfigFiles()
245

  
246
  def perspective_upload_file(self,params):
247
    return backend.UploadFile(*params)
248

  
249

  
250
  # os -----------------------
251

  
252
  def perspective_os_diagnose(self, params):
253
    os_list = backend.DiagnoseOS()
254
    if not os_list:
255
      # this catches also return values of 'False',
256
      # for which we can't iterate over
257
      return os_list
258
    result = []
259
    for data in os_list:
260
      if isinstance(data, objects.OS):
261
        result.append(data.Dumps())
262
      elif isinstance(data, errors.InvalidOS):
263
        result.append(data.args)
264
      else:
265
        raise errors.ProgrammerError, ("Invalid result from backend.DiagnoseOS"
266
                                       " (class %s, %s)" %
267
                                       (str(data.__class__), data))
268

  
269
    return result
270

  
271
  def perspective_os_get(self, params):
272
    name = params[0]
273
    try:
274
      os = backend.OSFromDisk(name).Dumps()
275
    except errors.InvalidOS, err:
276
      os = err.args
277
    return os
278

  
279
  # hooks -----------------------
280

  
281
  def perspective_hooks_runner(self, params):
282
    hpath, phase, env = params
283
    hr = backend.HooksRunner()
284
    return hr.RunHooks(hpath, phase, env)
285

  
286

  
287
class MyRealm:
288
  __implements__ = portal.IRealm
289
  def requestAvatar(self, avatarId, mind, *interfaces):
290
    if pb.IPerspective not in interfaces:
291
      raise NotImplementedError
292
    return pb.IPerspective, ServerObject(avatarId), lambda:None
293

  
294

  
295
def ParseOptions():
296
  """Parse the command line options.
297

  
298
  Returns:
299
    (options, args) as from OptionParser.parse_args()
300

  
301
  """
302
  parser = OptionParser(description="Ganeti node daemon",
303
                        usage="%prog [-f] [-d]",
304
                        version="%%prog (ganeti) %s" %
305
                        constants.RELEASE_VERSION)
306

  
307
  parser.add_option("-f", "--foreground", dest="fork",
308
                    help="Don't detach from the current terminal",
309
                    default=True, action="store_false")
310
  parser.add_option("-d", "--debug", dest="debug",
311
                    help="Enable some debug messages",
312
                    default=False, action="store_true")
313
  options, args = parser.parse_args()
314
  return options, args
315

  
316

  
317
def main():
318
  options, args = ParseOptions()
319
  for fname in (constants.SSL_CERT_FILE,):
320
    if not os.path.isfile(fname):
321
      print "config %s not there, will not run." % fname
322
      sys.exit(5)
323

  
324
  try:
325
    ss = ssconf.SimpleStore()
326
    port = ss.GetNodeDaemonPort()
327
    pwdata = ss.GetNodeDaemonPassword()
328
  except errors.ConfigurationError, err:
329
    print "Cluster configuration incomplete: '%s'" % str(err)
330
    sys.exit(5)
331

  
332
  # become a daemon
333
  if options.fork:
334
    createDaemon()
335

  
336
  logger.SetupLogging(twisted_workaround=True, debug=options.debug,
337
                      program="ganeti-noded")
338

  
339
  p = portal.Portal(MyRealm())
340
  p.registerChecker(
341
    checkers.InMemoryUsernamePasswordDatabaseDontUse(master_node=pwdata))
342
  reactor.listenSSL(port, pb.PBServerFactory(p), ServerContextFactory())
343
  reactor.run()
344

  
345

  
346
def createDaemon():
347
  """Detach a process from the controlling terminal and run it in the
348
  background as a daemon.
349
  """
350
  UMASK = 077
351
  WORKDIR = "/"
352
  # Default maximum for the number of available file descriptors.
353
  if 'SC_OPEN_MAX' in os.sysconf_names:
354
    try:
355
      MAXFD = os.sysconf('SC_OPEN_MAX')
356
      if MAXFD < 0:
357
        MAXFD = 1024
358
    except OSError:
359
      MAXFD = 1024
360
  else:
361
    MAXFD = 1024
362
  # The standard I/O file descriptors are redirected to /dev/null by default.
363
  #REDIRECT_TO = getattr(os, "devnull", "/dev/null")
364
  REDIRECT_TO = constants.LOG_NODESERVER
365
  try:
366
    pid = os.fork()
367
  except OSError, e:
368
    raise Exception, "%s [%d]" % (e.strerror, e.errno)
369
  if (pid == 0):	# The first child.
370
    os.setsid()
371
    try:
372
      pid = os.fork()	# Fork a second child.
373
    except OSError, e:
374
      raise Exception, "%s [%d]" % (e.strerror, e.errno)
375
    if (pid == 0):	# The second child.
376
      os.chdir(WORKDIR)
377
      os.umask(UMASK)
378
    else:
379
      # exit() or _exit()?  See below.
380
      os._exit(0)	# Exit parent (the first child) of the second child.
381
  else:
382
    os._exit(0)	# Exit parent of the first child.
383
  maxfd = resource.getrlimit(resource.RLIMIT_NOFILE)[1]
384
  if (maxfd == resource.RLIM_INFINITY):
385
    maxfd = MAXFD
386

  
387
  # Iterate through and close all file descriptors.
388
  for fd in range(0, maxfd):
389
    try:
390
      os.close(fd)
391
    except OSError:	# ERROR, fd wasn't open to begin with (ignored)
392
      pass
393
  os.open(REDIRECT_TO, os.O_RDWR|os.O_CREAT|os.O_APPEND) # standard input (0)
394
  # Duplicate standard input to standard output and standard error.
395
  os.dup2(0, 1)			# standard output (1)
396
  os.dup2(0, 2)			# standard error (2)
397
  return(0)
398

  
399

  
400
if __name__=='__main__':
401
  main()
b/daemons/ganeti-watcher
1
#!/usr/bin/python
2
#
3

  
4
# Copyright (C) 2006, 2007 Google Inc.
5
#
6
# This program is free software; you can redistribute it and/or modify
7
# it under the terms of the GNU General Public License as published by
8
# the Free Software Foundation; either version 2 of the License, or
9
# (at your option) any later version.
10
#
11
# This program is distributed in the hope that it will be useful, but
12
# WITHOUT ANY WARRANTY; without even the implied warranty of
13
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14
# General Public License for more details.
15
#
16
# You should have received a copy of the GNU General Public License
17
# along with this program; if not, write to the Free Software
18
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19
# 02110-1301, USA.
20

  
21

  
22
"""Tool to restart erronously downed virtual machines.
23

  
24
This program and set of classes implement a watchdog to restart
25
virtual machines in a Ganeti cluster that have crashed or been killed
26
by a node reboot.  Run from cron or similar.
27
"""
28

  
29

  
30
LOGFILE = '/var/log/ganeti/watcher.log'
31
MAXTRIES = 5
32
BAD_STATES = ['stopped']
33
HELPLESS_STATES = ['(node down)']
34
NOTICE = 'NOTICE'
35
ERROR = 'ERROR'
36

  
37
import os
38
import sys
39
import time
40
import fcntl
41
import errno
42
from optparse import OptionParser
43

  
44

  
45
from ganeti import utils
46
from ganeti import constants
47

  
48

  
49
class Error(Exception):
50
  """Generic custom error class."""
51
  pass
52

  
53

  
54
def Indent(s, prefix='| '):
55
  """Indent a piece of text with a given prefix before each line.
56

  
57
  Args:
58
    s: The string to indent
59
    prefix: The string to prepend each line.
60
  """
61
  return "%s%s\n" % (prefix, ('\n' + prefix).join(s.splitlines()))
62

  
63

  
64
def DoCmd(cmd):
65
  """Run a shell command.
66

  
67
  Args:
68
    cmd: the command to run.
69

  
70
  Raises CommandError with verbose commentary on error.
71
  """
72
  res = utils.RunCmd(cmd)
73

  
74
  if res.failed:
75
    raise Error("Command %s failed:\n%s\nstdout:\n%sstderr:\n%s" %
76
                (repr(cmd),
77
                 Indent(res.fail_reason),
78
                 Indent(res.stdout),
79
                 Indent(res.stderr)))
80

  
81
  return res
82

  
83

  
84
class RestarterState(object):
85
  """Interface to a state file recording restart attempts.
86

  
87
  Methods:
88
    Open(): open, lock, read and parse the file.
89
            Raises StandardError on lock contention.
90

  
91
    NumberOfAttempts(name): returns the number of times in succession
92
                            a restart has been attempted of the named instance.
93

  
94
    RecordAttempt(name, when): records one restart attempt of name at
95
                               time in when.
96

  
97
    Remove(name): remove record given by name, if exists.
98

  
99
    Save(name): saves all records to file, releases lock and closes file.
100
  """
101
  def __init__(self):
102
    # The two-step dance below is necessary to allow both opening existing
103
    # file read/write and creating if not existing.  Vanilla open will truncate
104
    # an existing file -or- allow creating if not existing.
105
    f = os.open(constants.WATCHER_STATEFILE, os.O_RDWR | os.O_CREAT)
106
    f = os.fdopen(f, 'w+')
107

  
108
    try:
109
      fcntl.flock(f.fileno(), fcntl.LOCK_EX|fcntl.LOCK_NB)
110
    except IOError, x:
111
      if x.errno == errno.EAGAIN:
112
        raise StandardError('State file already locked')
113
      raise
114

  
115
    self.statefile = f
116
    self.inst_map = {}
117

  
118
    for line in f:
119
      name, when, count = line.rstrip().split(':')
120

  
121
      when = int(when)
122
      count = int(count)
123

  
124
      self.inst_map[name] = (when, count)
125

  
126
  def NumberOfAttempts(self, instance):
127
    """Returns number of previous restart attempts.
128

  
129
    Args:
130
      instance - the instance to look up.
131
    """
132
    assert self.statefile
133

  
134
    if instance.name in self.inst_map:
135
      return self.inst_map[instance.name][1]
136

  
137
    return 0
138

  
139
  def RecordAttempt(self, instance):
140
    """Record a restart attempt.
141

  
142
    Args:
143
      instance - the instance being restarted
144
    """
145
    assert self.statefile
146

  
147
    when = time.time()
148

  
149
    self.inst_map[instance.name] = (when, 1 + self.NumberOfAttempts(instance))
150

  
151
  def Remove(self, instance):
152
    """Update state to reflect that a machine is running, i.e. remove record
153

  
154
    Args:
155
      instance - the instance to remove from books
156

  
157
    This method removes the record for a named instance
158
    """
159
    assert self.statefile
160

  
161
    if instance.name in self.inst_map:
162
      del self.inst_map[instance.name]
163

  
164
  def Save(self):
165
    """Save records to file, then unlock and close file.
166
    """
167
    assert self.statefile
168

  
169
    self.statefile.seek(0)
170
    self.statefile.truncate()
171

  
172
    for name in self.inst_map:
173
      print >> self.statefile, "%s:%d:%d" % ((name,) + self.inst_map[name])
174

  
175
    fcntl.flock(self.statefile.fileno(), fcntl.LOCK_UN)
176

  
177
    self.statefile.close()
178
    self.statefile = None
179

  
180

  
181
class Instance(object):
182
  """Abstraction for a Virtual Machine instance.
183

  
184
  Methods:
185
    Restart(): issue a command to restart the represented machine.
186
  """
187
  def __init__(self, name, state):
188
    self.name = name
189
    self.state = state
190

  
191
  def Restart(self):
192
    DoCmd(['gnt-instance', 'startup', '--lock-retries=15', self.name])
193

  
194

  
195
class InstanceList(object):
196
  """The set of Virtual Machine instances on a cluster.
197
  """
198
  cmd = ['gnt-instance', 'list', '--lock-retries=15',
199
         '-o', 'name,admin_state,oper_state', '--no-headers', '--separator=:']
200

  
201
  def __init__(self):
202
    res = DoCmd(self.cmd)
203

  
204
    lines = res.stdout.splitlines()
205

  
206
    self.instances = []
207
    for line in lines:
208
      fields = [fld.strip() for fld in line.split(':')]
209

  
210
      if len(fields) != 3:
211
        continue
212
      if fields[1] == "no": #no autostart, we don't care about this instance
213
        continue
214
      name, status = fields[0], fields[2]
215

  
216
      self.instances.append(Instance(name, status))
217

  
218
  def __iter__(self):
219
    return self.instances.__iter__()
220

  
221

  
222
class Message(object):
223
  """Encapsulation of a notice or error message.
224
  """
225
  def __init__(self, level, msg):
226
    self.level = level
227
    self.msg = msg
228
    self.when = time.time()
229

  
230
  def __str__(self):
231
    return self.level + ' ' + time.ctime(self.when) + '\n' + Indent(self.msg)
232

  
233

  
234
class Restarter(object):
235
  """Encapsulate the logic for restarting erronously halted virtual machines.
236

  
237
  The calling program should periodically instantiate me and call Run().
238
  This will traverse the list of instances, and make up to MAXTRIES attempts
239
  to restart machines that are down.
240
  """
241
  def __init__(self):
242
    self.instances = InstanceList()
243
    self.messages = []
244

  
245
  def Run(self):
246
    """Make a pass over the list of instances, restarting downed ones.
247
    """
248
    notepad = RestarterState()
249

  
250
    for instance in self.instances:
251
      if instance.state in BAD_STATES:
252
        n = notepad.NumberOfAttempts(instance)
253

  
254
        if n > MAXTRIES:
255
          # stay quiet.
256
          continue
257
        elif n < MAXTRIES:
258
          last = " (Attempt #%d)" % (n + 1)
259
        else:
260
          notepad.RecordAttempt(instance)
261
          self.messages.append(Message(ERROR, "Could not restart %s for %d"
262
                                       " times, giving up..." %
263
                                       (instance.name, MAXTRIES)))
264
          continue
265
        try:
266
          self.messages.append(Message(NOTICE,
267
                                       "Restarting %s%s." %
268
                                       (instance.name, last)))
269
          instance.Restart()
270
        except Error, x:
271
          self.messages.append(Message(ERROR, str(x)))
272

  
273
        notepad.RecordAttempt(instance)
274
      elif instance.state in HELPLESS_STATES:
275
        if notepad.NumberOfAttempts(instance):
276
          notepad.Remove(instance)
277
      else:
278
        if notepad.NumberOfAttempts(instance):
279
          notepad.Remove(instance)
280
          msg = Message(NOTICE,
281
                        "Restart of %s succeeded." % instance.name)
282
          self.messages.append(msg)
283

  
284
    notepad.Save()
285

  
286
  def WriteReport(self, logfile):
287
    """
288
    Log all messages to file.
289

  
290
    Args:
291
      logfile: file object open for writing (the log file)
292
    """
293
    for msg in self.messages:
294
      print >> logfile, str(msg)
295

  
296

  
297
def ParseOptions():
298
  """Parse the command line options.
299

  
300
  Returns:
301
    (options, args) as from OptionParser.parse_args()
302

  
303
  """
304
  parser = OptionParser(description="Ganeti cluster watcher",
305
                        usage="%prog [-d]",
306
                        version="%%prog (ganeti) %s" %
307
                        constants.RELEASE_VERSION)
308

  
309
  parser.add_option("-d", "--debug", dest="debug",
310
                    help="Don't redirect messages to the log file",
311
                    default=False, action="store_true")
312
  options, args = parser.parse_args()
313
  return options, args
314

  
315

  
316
def main():
317
  """Main function.
318

  
319
  """
320
  options, args = ParseOptions()
321

  
322
  if not options.debug:
323
    sys.stderr = sys.stdout = open(LOGFILE, 'a')
324

  
325
  try:
326
    restarter = Restarter()
327
    restarter.Run()
328
    restarter.WriteReport(sys.stdout)
329
  except Error, err:
330
    print err
331

  
332
if __name__ == '__main__':
333
  main()
b/docs/Makefile.am
1
docdir = $(datadir)/doc/$(PACKAGE)
2

  
3
dist_doc_DATA = hooks.html hooks.pdf
4
EXTRA_DIST = hooks.sgml
5

  
6
%.html: %.sgml
7
	docbook2html --nochunks $<
8

  
9
%.pdf: %.sgml
10
	docbook2pdf $<
b/docs/hooks.sgml
1
<!DOCTYPE article PUBLIC "-//OASIS//DTD DocBook V4.2//EN" [
2
]>
3
  <article class="specification">
4
  <articleinfo>
5
    <title>Ganeti customisation using hooks</title>
6
  </articleinfo>
7
  <para>Documents ganeti version 1.2</para>
8
  <section>
9
    <title>Introduction</title>
10

  
11
    <para>
12
      In order to allow customisation of operations, ganeti will run
13
      scripts under <filename
14
      class="directory">/etc/ganeti/hooks</filename> based on certain
15
      rules.
16
    </para>
17

  
18
      <para>This is similar to the <filename
19
      class="directory">/etc/network/</filename> structure present in
20
      Debian for network interface handling.</para>
21

  
22
    </section>
23

  
24

  
25
    <section>
26
      <title>Organisation</title>
27

  
28
      <para>For every operation, two sets of scripts are run:
29

  
30
      <itemizedlist>
31
          <listitem>
32
            <simpara>pre phase (for authorization/checking)</simpara>
33
          </listitem>
34
          <listitem>
35
            <simpara>post phase (for logging)</simpara>
36
          </listitem>
37
        </itemizedlist>
38
      </para>
39

  
40
      <para>Also, for each operation, the scripts are run on one or
41
      more nodes, depending on the operation type.</para>
42

  
43
      <para>Note that, even though we call them scripts, we are
44
      actually talking about any executable.</para>
45

  
46
      <section>
47
        <title><emphasis>pre</emphasis> scripts</title>
48

  
49
        <para>The <emphasis>pre</emphasis> scripts have a definite
50
        target: to check that the operation is allowed given the
51
        site-specific constraints. You could have, for example, a rule
52
        that says every new instance is required to exists in a
53
        database; to implement this, you could write a script that
54
        checks the new instance parameters against your
55
        database.</para>
56

  
57
        <para>The objective of these scripts should be their return
58
        code (zero or non-zero for success and failure). However, if
59
        they modify the environment in any way, they should be
60
        idempotent, as failed executions could be restarted and thus
61
        the script(s) run again with exactly the same
62
        parameters.</para>
63

  
64
      </section>
65

  
66
      <section>
67
        <title><emphasis>post</emphasis> scripts</title>
68

  
69
        <para>These scripts should do whatever you need as a reaction
70
        to the completion of an operation. Their return code is not
71
        checked (but logged), and they should not depend on the fact
72
        that the <emphasis>pre</emphasis> scripts have been
73
        run.</para>
74

  
75
      </section>
76

  
77
      <section>
78
        <title>Naming</title>
79

  
80
        <para>The allowed names for the scripts consist of (similar to
81
        <citerefentry> <refentrytitle>run-parts</refentrytitle>
82
        <manvolnum>8</manvolnum> </citerefentry>) upper and lower
83
        case, digits, underscores and hyphens. In other words, the
84
        regexp
85
        <computeroutput>^[a-zA-Z0-9_-]+$</computeroutput>. Also,
86
        non-executable scripts will be ignored.
87
        </para>
88
      </section>
89

  
90
      <section>
91
        <title>Order of execution</title>
92

  
93
        <para>On a single node, the scripts in a directory are run in
94
        lexicographic order (more exactly, the python string
95
        comparison order). It is advisable to implement the usual
96
        <emphasis>NN-name</emphasis> convention where
97
        <emphasis>NN</emphasis> is a two digit number.</para>
98

  
99
        <para>For an operation whose hooks are run on multiple nodes,
100
        there is no specific ordering of nodes with regard to hooks
101
        execution; you should assume that the scripts are run in
102
        parallel on the target nodes (keeping on each node the above
103
        specified ordering).  If you need any kind of inter-node
104
        synchronisation, you have to implement it yourself in the
105
        scripts.</para>
106

  
107
      </section>
108

  
109
      <section>
110
        <title>Execution environment</title>
111

  
112
        <para>The scripts will be run as follows:
113
          <itemizedlist>
114
          <listitem>
115
            <simpara>no command line arguments</simpara>
116
          </listitem>
117
            <listitem>
118
              <simpara>no controlling <acronym>tty</acronym></simpara>
119
            </listitem>
120
            <listitem>
121
              <simpara><varname>stdin</varname> is
122
              actually <filename>/dev/null</filename></simpara>
123
            </listitem>
124
            <listitem>
125
              <simpara><varname>stdout</varname> and
126
              <varname>stderr</varname> are directed to
127
              files</simpara>
128
            </listitem>
129
          <listitem>
130
            <simpara>the <varname>PATH</varname> is reset to
131
            <literal>/sbin:/bin:/usr/sbin:/usr/bin</literal></simpara>
132
          </listitem>
133
          <listitem>
134
            <simpara>the environment is cleared, and only
135
            ganeti-specific variables will be left</simpara>
136
          </listitem>
137
          </itemizedlist>
138

  
139
        </para>
140

  
141
      <para>All informations about the cluster is passed using
142
      environment variables. Different operations will have sligthly
143
      different environments, but most of the variables are
144
      common.</para>
145

  
146
    </section>
147

  
148

  
149
    <section>
150
      <title>Operation list</title>
151
      <table>
152
        <title>Operation list</title>
153
        <tgroup cols="7">
154
          <colspec>
155
          <colspec>
156
          <colspec>
157
          <colspec>
158
          <colspec>
159
          <colspec colname="prehooks">
160
          <colspec colname="posthooks">
161
          <spanspec namest="prehooks" nameend="posthooks"
162
            spanname="bothhooks">
163
          <thead>
164
            <row>
165
              <entry>Operation ID</entry>
166
              <entry>Directory prefix</entry>
167
              <entry>Description</entry>
168
              <entry>Command</entry>
169
              <entry>Supported env. variables</entry>
170
              <entry><emphasis>pre</emphasis> hooks</entry>
171
              <entry><emphasis>post</emphasis> hooks</entry>
172
            </row>
173
          </thead>
174
          <tbody>
175
            <row>
176
              <entry>OP_INIT_CLUSTER</entry>
177
              <entry><filename class="directory">cluster-init</filename></entry>
178
              <entry>Initialises the cluster</entry>
179
              <entry><computeroutput>gnt-cluster init</computeroutput></entry>
180
              <entry><constant>CLUSTER</constant>, <constant>MASTER</constant></entry>
181
              <entry spanname="bothhooks">master node, cluster name</entry>
182
            </row>
183
            <row>
184
              <entry>OP_MASTER_FAILOVER</entry>
185
              <entry><filename class="directory">master-failover</filename></entry>
186
              <entry>Changes the master</entry>
187
              <entry><computeroutput>gnt-cluster master-failover</computeroutput></entry>
188
              <entry><constant>OLD_MASTER</constant>, <constant>NEW_MASTER</constant></entry>
189
              <entry>the new master</entry>
190
              <entry>all nodes</entry>
191
            </row>
192
            <row>
193
              <entry>OP_ADD_NODE</entry>
194
              <entry><filename class="directory">node-add</filename></entry>
195
              <entry>Adds a new node to the cluster</entry>
196
              <entry><computeroutput>gnt-node add</computeroutput></entry>
197
              <entry><constant>NODE_NAME</constant>, <constant>NODE_PIP</constant>, <constant>NODE_SIP</constant></entry>
198
              <entry>all existing nodes</entry>
199
              <entry>all existing nodes plus the new node</entry>
200
            </row>
201
            <row>
202
              <entry>OP_REMOVE_NODE</entry>
203
              <entry><filename class="directory">node-remove</filename></entry>
204
              <entry>Removes a node from the cluster</entry>
205
              <entry><computeroutput>gnt-node remove</computeroutput></entry>
206
              <entry><constant>NODE_NAME</constant></entry>
207
              <entry spanname="bothhooks">all existing nodes except the removed node</entry>
208
            </row>
209
            <row>
210
              <entry>OP_INSTANCE_ADD</entry>
211
              <entry><filename class="directory">instance-add</filename></entry>
212
              <entry>Creates a new instance</entry>
213
              <entry><computeroutput>gnt-instance add</computeroutput></entry>
214
              <entry><constant>INSTANCE_NAME</constant>, <constant>INSTANCE_PRIMARY</constant>, <constant>INSTANCE_SECONDARIES</constant>, <constant>DISK_TEMPLATE</constant>, <constant>MEM_SIZE</constant>, <constant>DISK_SIZE</constant>, <constant>SWAP_SIZE</constant>, <constant>VCPUS</constant>, <constant>INSTANCE_IP</constant>, <constant>INSTANCE_ADD_MODE</constant>, <constant>SRC_NODE</constant>, <constant>SRC_PATH</constant>, <constant>SRC_IMAGE</constant></entry>
215
              <entry spanname="bothhooks" morerows="4">master node, primary and
216
                   secondary nodes</entry>
217
            </row>
218
            <row>
219
              <entry>OP_BACKUP_EXPORT</entry>
220
              <entry><filename class="directory">instance-export</filename></entry>
221
              <entry>Export the instance</entry>
222
              <entry><computeroutput>gnt-backup export</computeroutput></entry>
223
              <entry><constant>INSTANCE_NAME</constant>, <constant>EXPORT_NODE</constant>, <constant>EXPORT_DO_SHUTDOWN</constant></entry>
224
            </row>
225
            <row>
226
              <entry>OP_INSTANCE_START</entry>
227
              <entry><filename class="directory">instance-start</filename></entry>
228
              <entry>Starts an instance</entry>
229
              <entry><computeroutput>gnt-instance start</computeroutput></entry>
230
              <entry><constant>INSTANCE_NAME</constant>, <constant>INSTANCE_PRIMARY</constant>, <constant>INSTANCE_SECONDARIES</constant>, <constant>FORCE</constant></entry>
231
            </row>
232
            <row>
233
              <entry>OP_INSTANCE_SHUTDOWN</entry>
234
              <entry><filename class="directory">instance-shutdown</filename></entry>
235
              <entry>Stops an instance</entry>
236
              <entry><computeroutput>gnt-instance shutdown</computeroutput></entry>
237
              <entry><constant>INSTANCE_NAME</constant>, <constant>INSTANCE_PRIMARY</constant>, <constant>INSTANCE_SECONDARIES</constant></entry>
238
            </row>
239
            <row>
240
              <entry>OP_INSTANCE_MODIFY</entry>
241
              <entry><filename class="directory">instance-modify</filename></entry>
242
              <entry>Modifies the instance parameters.</entry>
243
              <entry><computeroutput>gnt-instance modify</computeroutput></entry>
244
              <entry><constant>INSTANCE_NAME</constant>, <constant>MEM_SIZE</constant>, <constant>VCPUS</constant>, <constant>INSTANCE_IP</constant></entry>
245
            </row>
246
            <row>
247
              <entry>OP_INSTANCE_FAILOVER</entry>
248
              <entry><filename class="directory">instance-failover</filename></entry>
249
              <entry>Failover an instance</entry>
250
              <entry><computeroutput>gnt-instance start</computeroutput></entry>
251
              <entry><constant>INSTANCE_NAME</constant>, <constant>INSTANCE_PRIMARY</constant>, <constant>INSTANCE_SECONDARIES</constant>, <constant>IGNORE_CONSISTENCY</constant></entry>
252
            </row>
253
            <row>
254
              <entry>OP_INSTANCE_REMOVE</entry>
255
              <entry><filename class="directory">instance-remove</filename></entry>
256
              <entry>Remove an instance</entry>
257
              <entry><computeroutput>gnt-instance remove</computeroutput></entry>
258
              <entry><constant>INSTANCE_NAME</constant>, <constant>INSTANCE_PRIMARY</constant>, <constant>INSTANCE_SECONDARIES</constant></entry>
259
            </row>
260
            <row>
261
              <entry>OP_INSTANCE_ADD_MDDRBD</entry>
262
              <entry><filename class="directory">mirror-add</filename></entry>
263
              <entry>Adds a mirror component</entry>
264
              <entry><computeroutput>gnt-instance add-mirror</computeroutput></entry>
265
              <entry><constant>INSTANCE_NAME</constant>, <constant>NEW_SECONDARY</constant>, <constant>DISK_NAME</constant></entry>
266
            </row>
267
            <row>
268
              <entry>OP_INSTANCE_REMOVE_MDDRBD</entry>
269
              <entry><filename class="directory">mirror-remove</filename></entry>
270
              <entry>Removes a mirror component</entry>
271
              <entry><computeroutput>gnt-instance remove-mirror</computeroutput></entry>
272
              <entry><constant>INSTANCE_NAME</constant>, <constant>OLD_SECONDARY</constant>, <constant>DISK_NAME</constant>, <constant>DISK_ID</constant></entry>
273
            </row>
274
            <row>
... This diff was truncated because it exceeds the maximum size that can be displayed.

Also available in: Unified diff