Statistics
| Branch: | Tag: | Revision:

root / lib / bootstrap.py @ f3aebf6f

History | View | Annotate | Download (42.6 kB)

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

24 a0c9f010 Michael Hanselmann
"""
25 a0c9f010 Michael Hanselmann
26 a0c9f010 Michael Hanselmann
import os
27 a0c9f010 Michael Hanselmann
import os.path
28 a0c9f010 Michael Hanselmann
import re
29 b1b6ea87 Iustin Pop
import logging
30 d693c864 Iustin Pop
import time
31 a698cdbb Michael Hanselmann
import tempfile
32 a0c9f010 Michael Hanselmann
33 3039e2dc Helga Velroyen
from ganeti.cmdlib import cluster
34 4869595d Petr Pudlak
import ganeti.rpc.node as rpc
35 a0c9f010 Michael Hanselmann
from ganeti import ssh
36 a0c9f010 Michael Hanselmann
from ganeti import utils
37 a0c9f010 Michael Hanselmann
from ganeti import errors
38 a0c9f010 Michael Hanselmann
from ganeti import config
39 a0c9f010 Michael Hanselmann
from ganeti import constants
40 b9eeeb02 Michael Hanselmann
from ganeti import objects
41 a0c9f010 Michael Hanselmann
from ganeti import ssconf
42 a33848a5 Guido Trotter
from ganeti import serializer
43 a5728081 Guido Trotter
from ganeti import hypervisor
44 cde49218 Helga Velroyen
from ganeti.storage import drbd
45 3039e2dc Helga Velroyen
from ganeti.storage import filestorage
46 a744b676 Manuel Franceschini
from ganeti import netutils
47 3b6b6129 Michael Hanselmann
from ganeti import luxi
48 ff699aa9 Michael Hanselmann
from ganeti import jstore
49 7ede9c6a Michael Hanselmann
from ganeti import pathutils
50 9cdea43f Petr Pudlak
from ganeti import runtime
51 3b6b6129 Michael Hanselmann
52 a0c9f010 Michael Hanselmann
53 88b92fe3 Guido Trotter
# ec_id for InitConfig's temporary reservation manager
54 88b92fe3 Guido Trotter
_INITCONF_ECID = "initconfig-ecid"
55 88b92fe3 Guido Trotter
56 3b6b6129 Michael Hanselmann
#: After how many seconds daemon must be responsive
57 3b6b6129 Michael Hanselmann
_DAEMON_READY_TIMEOUT = 10.0
58 3b6b6129 Michael Hanselmann
59 e38220e4 Michael Hanselmann
60 531baf8e Iustin Pop
def _InitSSHSetup():
61 a0c9f010 Michael Hanselmann
  """Setup the SSH configuration for the cluster.
62 a0c9f010 Michael Hanselmann

63 a0c9f010 Michael Hanselmann
  This generates a dsa keypair for root, adds the pub key to the
64 a0c9f010 Michael Hanselmann
  permitted hosts and adds the hostkey to its own known hosts.
65 a0c9f010 Michael Hanselmann

66 a0c9f010 Michael Hanselmann
  """
67 052783ff Michael Hanselmann
  priv_key, pub_key, auth_keys = ssh.GetUserFiles(constants.SSH_LOGIN_USER)
68 a0c9f010 Michael Hanselmann
69 a0c9f010 Michael Hanselmann
  for name in priv_key, pub_key:
70 a0c9f010 Michael Hanselmann
    if os.path.exists(name):
71 a0c9f010 Michael Hanselmann
      utils.CreateBackup(name)
72 a0c9f010 Michael Hanselmann
    utils.RemoveFile(name)
73 a0c9f010 Michael Hanselmann
74 a0c9f010 Michael Hanselmann
  result = utils.RunCmd(["ssh-keygen", "-t", "dsa",
75 a0c9f010 Michael Hanselmann
                         "-f", priv_key,
76 a0c9f010 Michael Hanselmann
                         "-q", "-N", ""])
77 a0c9f010 Michael Hanselmann
  if result.failed:
78 a0c9f010 Michael Hanselmann
    raise errors.OpExecError("Could not generate ssh keypair, error %s" %
79 a0c9f010 Michael Hanselmann
                             result.output)
80 a0c9f010 Michael Hanselmann
81 7a0156dc Luca Bigliardi
  utils.AddAuthorizedKey(auth_keys, utils.ReadFile(pub_key))
82 a0c9f010 Michael Hanselmann
83 a0c9f010 Michael Hanselmann
84 c008906b Michael Hanselmann
def GenerateHmacKey(file_name):
85 c008906b Michael Hanselmann
  """Writes a new HMAC key.
86 c008906b Michael Hanselmann

87 c008906b Michael Hanselmann
  @type file_name: str
88 c008906b Michael Hanselmann
  @param file_name: Path to output file
89 c008906b Michael Hanselmann

90 c008906b Michael Hanselmann
  """
91 43575108 Michael Hanselmann
  utils.WriteFile(file_name, data="%s\n" % utils.GenerateSecret(), mode=0400,
92 43575108 Michael Hanselmann
                  backup=True)
93 43575108 Michael Hanselmann
94 43575108 Michael Hanselmann
95 b3cc1646 Helga Velroyen
# pylint: disable=R0913
96 b6267745 Andrea Spadaccini
def GenerateClusterCrypto(new_cluster_cert, new_rapi_cert, new_spice_cert,
97 b3cc1646 Helga Velroyen
                          new_confd_hmac_key, new_cds,
98 b6267745 Andrea Spadaccini
                          rapi_cert_pem=None, spice_cert_pem=None,
99 b6267745 Andrea Spadaccini
                          spice_cacert_pem=None, cds=None,
100 7ede9c6a Michael Hanselmann
                          nodecert_file=pathutils.NODED_CERT_FILE,
101 7ede9c6a Michael Hanselmann
                          rapicert_file=pathutils.RAPI_CERT_FILE,
102 7ede9c6a Michael Hanselmann
                          spicecert_file=pathutils.SPICE_CERT_FILE,
103 7ede9c6a Michael Hanselmann
                          spicecacert_file=pathutils.SPICE_CACERT_FILE,
104 7ede9c6a Michael Hanselmann
                          hmackey_file=pathutils.CONFD_HMAC_KEY,
105 7ede9c6a Michael Hanselmann
                          cds_file=pathutils.CLUSTER_DOMAIN_SECRET_FILE):
106 43575108 Michael Hanselmann
  """Updates the cluster certificates, keys and secrets.
107 43575108 Michael Hanselmann

108 43575108 Michael Hanselmann
  @type new_cluster_cert: bool
109 43575108 Michael Hanselmann
  @param new_cluster_cert: Whether to generate a new cluster certificate
110 43575108 Michael Hanselmann
  @type new_rapi_cert: bool
111 43575108 Michael Hanselmann
  @param new_rapi_cert: Whether to generate a new RAPI certificate
112 b6267745 Andrea Spadaccini
  @type new_spice_cert: bool
113 b6267745 Andrea Spadaccini
  @param new_spice_cert: Whether to generate a new SPICE certificate
114 6b7d5878 Michael Hanselmann
  @type new_confd_hmac_key: bool
115 6b7d5878 Michael Hanselmann
  @param new_confd_hmac_key: Whether to generate a new HMAC key
116 3db3eb2a Michael Hanselmann
  @type new_cds: bool
117 3db3eb2a Michael Hanselmann
  @param new_cds: Whether to generate a new cluster domain secret
118 43575108 Michael Hanselmann
  @type rapi_cert_pem: string
119 43575108 Michael Hanselmann
  @param rapi_cert_pem: New RAPI certificate in PEM format
120 b6267745 Andrea Spadaccini
  @type spice_cert_pem: string
121 b6267745 Andrea Spadaccini
  @param spice_cert_pem: New SPICE certificate in PEM format
122 b6267745 Andrea Spadaccini
  @type spice_cacert_pem: string
123 b6267745 Andrea Spadaccini
  @param spice_cacert_pem: Certificate of the CA that signed the SPICE
124 b6267745 Andrea Spadaccini
                           certificate, in PEM format
125 3db3eb2a Michael Hanselmann
  @type cds: string
126 3db3eb2a Michael Hanselmann
  @param cds: New cluster domain secret
127 aeefe835 Iustin Pop
  @type nodecert_file: string
128 aeefe835 Iustin Pop
  @param nodecert_file: optional override of the node cert file path
129 aeefe835 Iustin Pop
  @type rapicert_file: string
130 aeefe835 Iustin Pop
  @param rapicert_file: optional override of the rapi cert file path
131 b6267745 Andrea Spadaccini
  @type spicecert_file: string
132 b6267745 Andrea Spadaccini
  @param spicecert_file: optional override of the spice cert file path
133 b6267745 Andrea Spadaccini
  @type spicecacert_file: string
134 b6267745 Andrea Spadaccini
  @param spicecacert_file: optional override of the spice CA cert file path
135 aeefe835 Iustin Pop
  @type hmackey_file: string
136 aeefe835 Iustin Pop
  @param hmackey_file: optional override of the hmac key file path
137 43575108 Michael Hanselmann

138 43575108 Michael Hanselmann
  """
139 b3cc1646 Helga Velroyen
  # pylint: disable=R0913
140 168c1de2 Michael Hanselmann
  # noded SSL certificate
141 60cc531d Helga Velroyen
  utils.GenerateNewSslCert(
142 ab4b1cf2 Helga Velroyen
    new_cluster_cert, nodecert_file, 1,
143 60cc531d Helga Velroyen
    "Generating new cluster certificate at %s" % nodecert_file)
144 43575108 Michael Hanselmann
145 6b7d5878 Michael Hanselmann
  # confd HMAC key
146 aeefe835 Iustin Pop
  if new_confd_hmac_key or not os.path.exists(hmackey_file):
147 aeefe835 Iustin Pop
    logging.debug("Writing new confd HMAC key to %s", hmackey_file)
148 aeefe835 Iustin Pop
    GenerateHmacKey(hmackey_file)
149 43575108 Michael Hanselmann
150 43575108 Michael Hanselmann
  if rapi_cert_pem:
151 43575108 Michael Hanselmann
    # Assume rapi_pem contains a valid PEM-formatted certificate and key
152 aeefe835 Iustin Pop
    logging.debug("Writing RAPI certificate at %s", rapicert_file)
153 aeefe835 Iustin Pop
    utils.WriteFile(rapicert_file, data=rapi_cert_pem, backup=True)
154 43575108 Michael Hanselmann
155 60cc531d Helga Velroyen
  else:
156 60cc531d Helga Velroyen
    utils.GenerateNewSslCert(
157 ab4b1cf2 Helga Velroyen
      new_rapi_cert, rapicert_file, 1,
158 60cc531d Helga Velroyen
      "Generating new RAPI certificate at %s" % rapicert_file)
159 c008906b Michael Hanselmann
160 b6267745 Andrea Spadaccini
  # SPICE
161 b6267745 Andrea Spadaccini
  spice_cert_exists = os.path.exists(spicecert_file)
162 b6267745 Andrea Spadaccini
  spice_cacert_exists = os.path.exists(spicecacert_file)
163 b6267745 Andrea Spadaccini
  if spice_cert_pem:
164 b6267745 Andrea Spadaccini
    # spice_cert_pem implies also spice_cacert_pem
165 b6267745 Andrea Spadaccini
    logging.debug("Writing SPICE certificate at %s", spicecert_file)
166 b6267745 Andrea Spadaccini
    utils.WriteFile(spicecert_file, data=spice_cert_pem, backup=True)
167 b6267745 Andrea Spadaccini
    logging.debug("Writing SPICE CA certificate at %s", spicecacert_file)
168 b6267745 Andrea Spadaccini
    utils.WriteFile(spicecacert_file, data=spice_cacert_pem, backup=True)
169 b6267745 Andrea Spadaccini
  elif new_spice_cert or not spice_cert_exists:
170 b6267745 Andrea Spadaccini
    if spice_cert_exists:
171 b6267745 Andrea Spadaccini
      utils.CreateBackup(spicecert_file)
172 b6267745 Andrea Spadaccini
    if spice_cacert_exists:
173 b6267745 Andrea Spadaccini
      utils.CreateBackup(spicecacert_file)
174 b6267745 Andrea Spadaccini
175 b6267745 Andrea Spadaccini
    logging.debug("Generating new self-signed SPICE certificate at %s",
176 b6267745 Andrea Spadaccini
                  spicecert_file)
177 ab4b1cf2 Helga Velroyen
    (_, cert_pem) = utils.GenerateSelfSignedSslCert(spicecert_file, 1)
178 b6267745 Andrea Spadaccini
179 b6267745 Andrea Spadaccini
    # Self-signed certificate -> the public certificate is also the CA public
180 b6267745 Andrea Spadaccini
    # certificate
181 b6267745 Andrea Spadaccini
    logging.debug("Writing the public certificate to %s",
182 b6267745 Andrea Spadaccini
                  spicecert_file)
183 b6267745 Andrea Spadaccini
    utils.io.WriteFile(spicecacert_file, mode=0400, data=cert_pem)
184 b6267745 Andrea Spadaccini
185 3db3eb2a Michael Hanselmann
  # Cluster domain secret
186 3db3eb2a Michael Hanselmann
  if cds:
187 fc0726b9 Michael Hanselmann
    logging.debug("Writing cluster domain secret to %s", cds_file)
188 fc0726b9 Michael Hanselmann
    utils.WriteFile(cds_file, data=cds, backup=True)
189 fc0726b9 Michael Hanselmann
190 fc0726b9 Michael Hanselmann
  elif new_cds or not os.path.exists(cds_file):
191 fc0726b9 Michael Hanselmann
    logging.debug("Generating new cluster domain secret at %s", cds_file)
192 fc0726b9 Michael Hanselmann
    GenerateHmacKey(cds_file)
193 3db3eb2a Michael Hanselmann
194 c008906b Michael Hanselmann
195 8f215968 Michael Hanselmann
def _InitGanetiServerSetup(master_name):
196 40a97d80 Michael Hanselmann
  """Setup the necessary configuration for the initial node daemon.
197 40a97d80 Michael Hanselmann

198 40a97d80 Michael Hanselmann
  This creates the nodepass file containing the shared password for
199 600535f0 Manuel Franceschini
  the cluster, generates the SSL certificate and starts the node daemon.
200 600535f0 Manuel Franceschini

201 600535f0 Manuel Franceschini
  @type master_name: str
202 600535f0 Manuel Franceschini
  @param master_name: Name of the master node
203 40a97d80 Michael Hanselmann

204 40a97d80 Michael Hanselmann
  """
205 43575108 Michael Hanselmann
  # Generate cluster secrets
206 b3cc1646 Helga Velroyen
  GenerateClusterCrypto(True, False, False, False, False)
207 4a34c5cf Guido Trotter
208 7ede9c6a Michael Hanselmann
  result = utils.RunCmd([pathutils.DAEMON_UTIL, "start", constants.NODED])
209 a0c9f010 Michael Hanselmann
  if result.failed:
210 a0c9f010 Michael Hanselmann
    raise errors.OpExecError("Could not start the node daemon, command %s"
211 a0c9f010 Michael Hanselmann
                             " had exitcode %s and error %s" %
212 a0c9f010 Michael Hanselmann
                             (result.cmd, result.exit_code, result.output))
213 a0c9f010 Michael Hanselmann
214 5627f375 Michael Hanselmann
  _WaitForNodeDaemon(master_name)
215 5627f375 Michael Hanselmann
216 5627f375 Michael Hanselmann
217 5627f375 Michael Hanselmann
def _WaitForNodeDaemon(node_name):
218 5627f375 Michael Hanselmann
  """Wait for node daemon to become responsive.
219 5627f375 Michael Hanselmann

220 5627f375 Michael Hanselmann
  """
221 d3833ebd Michael Hanselmann
  def _CheckNodeDaemon():
222 bd6d1202 Renรฉ Nussbaumer
    # Pylint bug <http://www.logilab.org/ticket/35642>
223 bd6d1202 Renรฉ Nussbaumer
    # pylint: disable=E1101
224 db04ce5d Michael Hanselmann
    result = rpc.BootstrapRunner().call_version([node_name])[node_name]
225 d3833ebd Michael Hanselmann
    if result.fail_msg:
226 d3833ebd Michael Hanselmann
      raise utils.RetryAgain()
227 8f215968 Michael Hanselmann
228 d3833ebd Michael Hanselmann
  try:
229 3b6b6129 Michael Hanselmann
    utils.Retry(_CheckNodeDaemon, 1.0, _DAEMON_READY_TIMEOUT)
230 d3833ebd Michael Hanselmann
  except utils.RetryTimeout:
231 5627f375 Michael Hanselmann
    raise errors.OpExecError("Node daemon on %s didn't answer queries within"
232 3b6b6129 Michael Hanselmann
                             " %s seconds" % (node_name, _DAEMON_READY_TIMEOUT))
233 3b6b6129 Michael Hanselmann
234 3b6b6129 Michael Hanselmann
235 3b6b6129 Michael Hanselmann
def _WaitForMasterDaemon():
236 3b6b6129 Michael Hanselmann
  """Wait for master daemon to become responsive.
237 3b6b6129 Michael Hanselmann

238 3b6b6129 Michael Hanselmann
  """
239 3b6b6129 Michael Hanselmann
  def _CheckMasterDaemon():
240 3b6b6129 Michael Hanselmann
    try:
241 3b6b6129 Michael Hanselmann
      cl = luxi.Client()
242 3b6b6129 Michael Hanselmann
      (cluster_name, ) = cl.QueryConfigValues(["cluster_name"])
243 3b6b6129 Michael Hanselmann
    except Exception:
244 3b6b6129 Michael Hanselmann
      raise utils.RetryAgain()
245 3b6b6129 Michael Hanselmann
246 3b6b6129 Michael Hanselmann
    logging.debug("Received cluster name %s from master", cluster_name)
247 3b6b6129 Michael Hanselmann
248 3b6b6129 Michael Hanselmann
  try:
249 3b6b6129 Michael Hanselmann
    utils.Retry(_CheckMasterDaemon, 1.0, _DAEMON_READY_TIMEOUT)
250 3b6b6129 Michael Hanselmann
  except utils.RetryTimeout:
251 3b6b6129 Michael Hanselmann
    raise errors.OpExecError("Master daemon didn't answer queries within"
252 3b6b6129 Michael Hanselmann
                             " %s seconds" % _DAEMON_READY_TIMEOUT)
253 5627f375 Michael Hanselmann
254 a0c9f010 Michael Hanselmann
255 a5da38fa Michael Hanselmann
def _WaitForSshDaemon(hostname, port, family):
256 a5da38fa Michael Hanselmann
  """Wait for SSH daemon to become responsive.
257 a5da38fa Michael Hanselmann

258 a5da38fa Michael Hanselmann
  """
259 a5da38fa Michael Hanselmann
  hostip = netutils.GetHostname(name=hostname, family=family).ip
260 a5da38fa Michael Hanselmann
261 a5da38fa Michael Hanselmann
  def _CheckSshDaemon():
262 a5da38fa Michael Hanselmann
    if netutils.TcpPing(hostip, port, timeout=1.0, live_port_needed=True):
263 a5da38fa Michael Hanselmann
      logging.debug("SSH daemon on %s:%s (IP address %s) has become"
264 a5da38fa Michael Hanselmann
                    " responsive", hostname, port, hostip)
265 a5da38fa Michael Hanselmann
    else:
266 a5da38fa Michael Hanselmann
      raise utils.RetryAgain()
267 a5da38fa Michael Hanselmann
268 a5da38fa Michael Hanselmann
  try:
269 a5da38fa Michael Hanselmann
    utils.Retry(_CheckSshDaemon, 1.0, _DAEMON_READY_TIMEOUT)
270 a5da38fa Michael Hanselmann
  except utils.RetryTimeout:
271 a5da38fa Michael Hanselmann
    raise errors.OpExecError("SSH daemon on %s:%s (IP address %s) didn't"
272 a5da38fa Michael Hanselmann
                             " become responsive within %s seconds" %
273 a5da38fa Michael Hanselmann
                             (hostname, port, hostip, _DAEMON_READY_TIMEOUT))
274 a5da38fa Michael Hanselmann
275 a5da38fa Michael Hanselmann
276 a698cdbb Michael Hanselmann
def RunNodeSetupCmd(cluster_name, node, basecmd, debug, verbose,
277 a9f33339 Petr Pudlak
                    use_cluster_key, ask_key, strict_host_check,
278 a9f33339 Petr Pudlak
                    port, data):
279 a698cdbb Michael Hanselmann
  """Runs a command to configure something on a remote machine.
280 a698cdbb Michael Hanselmann

281 a698cdbb Michael Hanselmann
  @type cluster_name: string
282 a698cdbb Michael Hanselmann
  @param cluster_name: Cluster name
283 a698cdbb Michael Hanselmann
  @type node: string
284 a698cdbb Michael Hanselmann
  @param node: Node name
285 a698cdbb Michael Hanselmann
  @type basecmd: string
286 a698cdbb Michael Hanselmann
  @param basecmd: Base command (path on the remote machine)
287 a698cdbb Michael Hanselmann
  @type debug: bool
288 a698cdbb Michael Hanselmann
  @param debug: Enable debug output
289 a698cdbb Michael Hanselmann
  @type verbose: bool
290 a698cdbb Michael Hanselmann
  @param verbose: Enable verbose output
291 a698cdbb Michael Hanselmann
  @type use_cluster_key: bool
292 a698cdbb Michael Hanselmann
  @param use_cluster_key: See L{ssh.SshRunner.BuildCmd}
293 a698cdbb Michael Hanselmann
  @type ask_key: bool
294 a698cdbb Michael Hanselmann
  @param ask_key: See L{ssh.SshRunner.BuildCmd}
295 a698cdbb Michael Hanselmann
  @type strict_host_check: bool
296 a698cdbb Michael Hanselmann
  @param strict_host_check: See L{ssh.SshRunner.BuildCmd}
297 a9f33339 Petr Pudlak
  @type port: int
298 a9f33339 Petr Pudlak
  @param port: The SSH port of the remote machine or None for the default
299 a698cdbb Michael Hanselmann
  @param data: JSON-serializable input data for script (passed to stdin)
300 a698cdbb Michael Hanselmann

301 a698cdbb Michael Hanselmann
  """
302 a698cdbb Michael Hanselmann
  cmd = [basecmd]
303 a698cdbb Michael Hanselmann
304 a698cdbb Michael Hanselmann
  # Pass --debug/--verbose to the external script if set on our invocation
305 a698cdbb Michael Hanselmann
  if debug:
306 a698cdbb Michael Hanselmann
    cmd.append("--debug")
307 a698cdbb Michael Hanselmann
308 a698cdbb Michael Hanselmann
  if verbose:
309 a698cdbb Michael Hanselmann
    cmd.append("--verbose")
310 a698cdbb Michael Hanselmann
311 a9f33339 Petr Pudlak
  if port is None:
312 a9f33339 Petr Pudlak
    port = netutils.GetDaemonPort(constants.SSH)
313 a9f33339 Petr Pudlak
314 e1874aa7 Michael Hanselmann
  family = ssconf.SimpleStore().GetPrimaryIPFamily()
315 e1874aa7 Michael Hanselmann
  srun = ssh.SshRunner(cluster_name,
316 e1874aa7 Michael Hanselmann
                       ipv6=(family == netutils.IP6Address.family))
317 a698cdbb Michael Hanselmann
  scmd = srun.BuildCmd(node, constants.SSH_LOGIN_USER,
318 a698cdbb Michael Hanselmann
                       utils.ShellQuoteArgs(cmd),
319 a698cdbb Michael Hanselmann
                       batch=False, ask_key=ask_key, quiet=False,
320 a698cdbb Michael Hanselmann
                       strict_host_check=strict_host_check,
321 a9f33339 Petr Pudlak
                       use_cluster_key=use_cluster_key,
322 a9f33339 Petr Pudlak
                       port=port)
323 a698cdbb Michael Hanselmann
324 a698cdbb Michael Hanselmann
  tempfh = tempfile.TemporaryFile()
325 a698cdbb Michael Hanselmann
  try:
326 a698cdbb Michael Hanselmann
    tempfh.write(serializer.DumpJson(data))
327 a698cdbb Michael Hanselmann
    tempfh.seek(0)
328 a698cdbb Michael Hanselmann
329 a698cdbb Michael Hanselmann
    result = utils.RunCmd(scmd, interactive=True, input_fd=tempfh)
330 a698cdbb Michael Hanselmann
  finally:
331 a698cdbb Michael Hanselmann
    tempfh.close()
332 a698cdbb Michael Hanselmann
333 a698cdbb Michael Hanselmann
  if result.failed:
334 a698cdbb Michael Hanselmann
    raise errors.OpExecError("Command '%s' failed: %s" %
335 a698cdbb Michael Hanselmann
                             (result.cmd, result.fail_reason))
336 a698cdbb Michael Hanselmann
337 a9f33339 Petr Pudlak
  _WaitForSshDaemon(node, port, family)
338 a5da38fa Michael Hanselmann
339 a698cdbb Michael Hanselmann
340 5030cff3 Helga Velroyen
def _InitFileStorageDir(file_storage_dir):
341 0e3baaf3 Iustin Pop
  """Initialize if needed the file storage.
342 0e3baaf3 Iustin Pop

343 0e3baaf3 Iustin Pop
  @param file_storage_dir: the user-supplied value
344 0e3baaf3 Iustin Pop
  @return: either empty string (if file storage was disabled at build
345 0e3baaf3 Iustin Pop
      time) or the normalized path to the storage directory
346 0e3baaf3 Iustin Pop

347 0e3baaf3 Iustin Pop
  """
348 0e3baaf3 Iustin Pop
  file_storage_dir = os.path.normpath(file_storage_dir)
349 0e3baaf3 Iustin Pop
350 0e3baaf3 Iustin Pop
  if not os.path.isabs(file_storage_dir):
351 0376655e Guido Trotter
    raise errors.OpPrereqError("File storage directory '%s' is not an absolute"
352 0376655e Guido Trotter
                               " path" % file_storage_dir, errors.ECODE_INVAL)
353 0e3baaf3 Iustin Pop
354 0e3baaf3 Iustin Pop
  if not os.path.exists(file_storage_dir):
355 0e3baaf3 Iustin Pop
    try:
356 0e3baaf3 Iustin Pop
      os.makedirs(file_storage_dir, 0750)
357 0e3baaf3 Iustin Pop
    except OSError, err:
358 0e3baaf3 Iustin Pop
      raise errors.OpPrereqError("Cannot create file storage directory"
359 0e3baaf3 Iustin Pop
                                 " '%s': %s" % (file_storage_dir, err),
360 0e3baaf3 Iustin Pop
                                 errors.ECODE_ENVIRON)
361 0e3baaf3 Iustin Pop
362 0e3baaf3 Iustin Pop
  if not os.path.isdir(file_storage_dir):
363 0e3baaf3 Iustin Pop
    raise errors.OpPrereqError("The file storage directory '%s' is not"
364 0e3baaf3 Iustin Pop
                               " a directory." % file_storage_dir,
365 0e3baaf3 Iustin Pop
                               errors.ECODE_ENVIRON)
366 5030cff3 Helga Velroyen
367 0e3baaf3 Iustin Pop
  return file_storage_dir
368 0e3baaf3 Iustin Pop
369 0e3baaf3 Iustin Pop
370 e8b5640e Helga Velroyen
def _PrepareFileBasedStorage(
371 e8b5640e Helga Velroyen
    enabled_disk_templates, file_storage_dir,
372 e8b5640e Helga Velroyen
    default_dir, file_disk_template,
373 e8b5640e Helga Velroyen
    init_fn=_InitFileStorageDir, acceptance_fn=None):
374 e8b5640e Helga Velroyen
  """Checks if a file-base storage type is enabled and inits the dir.
375 e8b5640e Helga Velroyen

376 e8b5640e Helga Velroyen
  @type enabled_disk_templates: list of string
377 e8b5640e Helga Velroyen
  @param enabled_disk_templates: list of enabled disk templates
378 e8b5640e Helga Velroyen
  @type file_storage_dir: string
379 e8b5640e Helga Velroyen
  @param file_storage_dir: the file storage directory
380 e8b5640e Helga Velroyen
  @type default_dir: string
381 e8b5640e Helga Velroyen
  @param default_dir: default file storage directory when C{file_storage_dir}
382 e8b5640e Helga Velroyen
      is 'None'
383 e8b5640e Helga Velroyen
  @type file_disk_template: string
384 5a904197 Santi Raffa
  @param file_disk_template: a disk template whose storage type is 'ST_FILE' or
385 5a904197 Santi Raffa
      'ST_SHARED_FILE'
386 e8b5640e Helga Velroyen
  @rtype: string
387 e8b5640e Helga Velroyen
  @returns: the name of the actual file storage directory
388 3039e2dc Helga Velroyen

389 3039e2dc Helga Velroyen
  """
390 5a904197 Santi Raffa
  assert (file_disk_template in utils.storage.GetDiskTemplatesOfStorageTypes(
391 5a904197 Santi Raffa
            constants.ST_FILE, constants.ST_SHARED_FILE
392 5a904197 Santi Raffa
         ))
393 5a904197 Santi Raffa
394 3039e2dc Helga Velroyen
  if file_storage_dir is None:
395 e8b5640e Helga Velroyen
    file_storage_dir = default_dir
396 3039e2dc Helga Velroyen
  if not acceptance_fn:
397 3039e2dc Helga Velroyen
    acceptance_fn = \
398 3039e2dc Helga Velroyen
        lambda path: filestorage.CheckFileStoragePathAcceptance(
399 3039e2dc Helga Velroyen
            path, exact_match_ok=True)
400 3039e2dc Helga Velroyen
401 3039e2dc Helga Velroyen
  cluster.CheckFileStoragePathVsEnabledDiskTemplates(
402 3039e2dc Helga Velroyen
      logging.warning, file_storage_dir, enabled_disk_templates)
403 3039e2dc Helga Velroyen
404 e8b5640e Helga Velroyen
  file_storage_enabled = file_disk_template in enabled_disk_templates
405 3039e2dc Helga Velroyen
  if file_storage_enabled:
406 3039e2dc Helga Velroyen
    try:
407 3039e2dc Helga Velroyen
      acceptance_fn(file_storage_dir)
408 3039e2dc Helga Velroyen
    except errors.FileStoragePathError as e:
409 3039e2dc Helga Velroyen
      raise errors.OpPrereqError(str(e))
410 3039e2dc Helga Velroyen
    result_file_storage_dir = init_fn(file_storage_dir)
411 3039e2dc Helga Velroyen
  else:
412 3039e2dc Helga Velroyen
    result_file_storage_dir = file_storage_dir
413 3039e2dc Helga Velroyen
  return result_file_storage_dir
414 3039e2dc Helga Velroyen
415 3039e2dc Helga Velroyen
416 e8b5640e Helga Velroyen
def _PrepareFileStorage(
417 e8b5640e Helga Velroyen
    enabled_disk_templates, file_storage_dir, init_fn=_InitFileStorageDir,
418 e8b5640e Helga Velroyen
    acceptance_fn=None):
419 e8b5640e Helga Velroyen
  """Checks if file storage is enabled and inits the dir.
420 e8b5640e Helga Velroyen

421 e8b5640e Helga Velroyen
  @see: C{_PrepareFileBasedStorage}
422 e8b5640e Helga Velroyen

423 e8b5640e Helga Velroyen
  """
424 e8b5640e Helga Velroyen
  return _PrepareFileBasedStorage(
425 e8b5640e Helga Velroyen
      enabled_disk_templates, file_storage_dir,
426 e8b5640e Helga Velroyen
      pathutils.DEFAULT_FILE_STORAGE_DIR, constants.DT_FILE,
427 e8b5640e Helga Velroyen
      init_fn=init_fn, acceptance_fn=acceptance_fn)
428 e8b5640e Helga Velroyen
429 e8b5640e Helga Velroyen
430 e8b5640e Helga Velroyen
def _PrepareSharedFileStorage(
431 e8b5640e Helga Velroyen
    enabled_disk_templates, file_storage_dir, init_fn=_InitFileStorageDir,
432 e8b5640e Helga Velroyen
    acceptance_fn=None):
433 e8b5640e Helga Velroyen
  """Checks if shared file storage is enabled and inits the dir.
434 e8b5640e Helga Velroyen

435 e8b5640e Helga Velroyen
  @see: C{_PrepareFileBasedStorage}
436 e8b5640e Helga Velroyen

437 e8b5640e Helga Velroyen
  """
438 e8b5640e Helga Velroyen
  return _PrepareFileBasedStorage(
439 e8b5640e Helga Velroyen
      enabled_disk_templates, file_storage_dir,
440 e8b5640e Helga Velroyen
      pathutils.DEFAULT_SHARED_FILE_STORAGE_DIR, constants.DT_SHARED_FILE,
441 e8b5640e Helga Velroyen
      init_fn=init_fn, acceptance_fn=acceptance_fn)
442 e8b5640e Helga Velroyen
443 e8b5640e Helga Velroyen
444 d3e6fd0e Santi Raffa
def _PrepareGlusterStorage(
445 d3e6fd0e Santi Raffa
    enabled_disk_templates, file_storage_dir, init_fn=_InitFileStorageDir,
446 d3e6fd0e Santi Raffa
    acceptance_fn=None):
447 d3e6fd0e Santi Raffa
  """Checks if gluster storage is enabled and inits the dir.
448 d3e6fd0e Santi Raffa

449 d3e6fd0e Santi Raffa
  @see: C{_PrepareFileBasedStorage}
450 d3e6fd0e Santi Raffa

451 d3e6fd0e Santi Raffa
  """
452 d3e6fd0e Santi Raffa
  return _PrepareFileBasedStorage(
453 d3e6fd0e Santi Raffa
      enabled_disk_templates, file_storage_dir,
454 d3e6fd0e Santi Raffa
      pathutils.DEFAULT_GLUSTER_STORAGE_DIR, constants.DT_GLUSTER,
455 d3e6fd0e Santi Raffa
      init_fn=init_fn, acceptance_fn=acceptance_fn)
456 d3e6fd0e Santi Raffa
457 d3e6fd0e Santi Raffa
458 5030cff3 Helga Velroyen
def _InitCheckEnabledDiskTemplates(enabled_disk_templates):
459 5030cff3 Helga Velroyen
  """Checks the sanity of the enabled disk templates.
460 5030cff3 Helga Velroyen

461 5030cff3 Helga Velroyen
  """
462 5030cff3 Helga Velroyen
  if not enabled_disk_templates:
463 5030cff3 Helga Velroyen
    raise errors.OpPrereqError("Enabled disk templates list must contain at"
464 5030cff3 Helga Velroyen
                               " least one member", errors.ECODE_INVAL)
465 5030cff3 Helga Velroyen
  invalid_disk_templates = \
466 5030cff3 Helga Velroyen
    set(enabled_disk_templates) - constants.DISK_TEMPLATES
467 5030cff3 Helga Velroyen
  if invalid_disk_templates:
468 5030cff3 Helga Velroyen
    raise errors.OpPrereqError("Enabled disk templates list contains invalid"
469 5030cff3 Helga Velroyen
                               " entries: %s" % invalid_disk_templates,
470 5030cff3 Helga Velroyen
                               errors.ECODE_INVAL)
471 5030cff3 Helga Velroyen
472 5030cff3 Helga Velroyen
473 d514e18b Helga Velroyen
def _RestrictIpolicyToEnabledDiskTemplates(ipolicy, enabled_disk_templates):
474 d514e18b Helga Velroyen
  """Restricts the ipolicy's disk templates to the enabled ones.
475 d514e18b Helga Velroyen

476 d514e18b Helga Velroyen
  This function clears the ipolicy's list of allowed disk templates from the
477 d514e18b Helga Velroyen
  ones that are not enabled by the cluster.
478 d514e18b Helga Velroyen

479 d514e18b Helga Velroyen
  @type ipolicy: dict
480 d514e18b Helga Velroyen
  @param ipolicy: the instance policy
481 d514e18b Helga Velroyen
  @type enabled_disk_templates: list of string
482 d514e18b Helga Velroyen
  @param enabled_disk_templates: the list of cluster-wide enabled disk
483 d514e18b Helga Velroyen
    templates
484 d514e18b Helga Velroyen

485 d514e18b Helga Velroyen
  """
486 d514e18b Helga Velroyen
  assert constants.IPOLICY_DTS in ipolicy
487 d514e18b Helga Velroyen
  allowed_disk_templates = ipolicy[constants.IPOLICY_DTS]
488 d514e18b Helga Velroyen
  restricted_disk_templates = list(set(allowed_disk_templates)
489 d514e18b Helga Velroyen
                                   .intersection(set(enabled_disk_templates)))
490 d514e18b Helga Velroyen
  ipolicy[constants.IPOLICY_DTS] = restricted_disk_templates
491 d514e18b Helga Velroyen
492 d514e18b Helga Velroyen
493 7796e1f8 Helga Velroyen
def _InitCheckDrbdHelper(drbd_helper, drbd_enabled):
494 af95196c Helga Velroyen
  """Checks the DRBD usermode helper.
495 af95196c Helga Velroyen

496 af95196c Helga Velroyen
  @type drbd_helper: string
497 af95196c Helga Velroyen
  @param drbd_helper: name of the DRBD usermode helper that the system should
498 af95196c Helga Velroyen
    use
499 af95196c Helga Velroyen

500 af95196c Helga Velroyen
  """
501 7796e1f8 Helga Velroyen
  if not drbd_enabled:
502 7796e1f8 Helga Velroyen
    return
503 7796e1f8 Helga Velroyen
504 af95196c Helga Velroyen
  if drbd_helper is not None:
505 af95196c Helga Velroyen
    try:
506 af95196c Helga Velroyen
      curr_helper = drbd.DRBD8.GetUsermodeHelper()
507 af95196c Helga Velroyen
    except errors.BlockDeviceError, err:
508 af95196c Helga Velroyen
      raise errors.OpPrereqError("Error while checking drbd helper"
509 7796e1f8 Helga Velroyen
                                 " (disable drbd with --enabled-disk-templates"
510 7796e1f8 Helga Velroyen
                                 " if you are not using drbd): %s" % str(err),
511 af95196c Helga Velroyen
                                 errors.ECODE_ENVIRON)
512 af95196c Helga Velroyen
    if drbd_helper != curr_helper:
513 af95196c Helga Velroyen
      raise errors.OpPrereqError("Error: requiring %s as drbd helper but %s"
514 af95196c Helga Velroyen
                                 " is the current helper" % (drbd_helper,
515 af95196c Helga Velroyen
                                                             curr_helper),
516 af95196c Helga Velroyen
                                 errors.ECODE_INVAL)
517 af95196c Helga Velroyen
518 af95196c Helga Velroyen
519 18bb6d28 Agata Murawska
def InitCluster(cluster_name, mac_prefix, # pylint: disable=R0913, R0914
520 5a8648eb Andrea Spadaccini
                master_netmask, master_netdev, file_storage_dir,
521 d3e6fd0e Santi Raffa
                shared_file_storage_dir, gluster_storage_dir,
522 d3e6fd0e Santi Raffa
                candidate_pool_size, secondary_ip=None,
523 5a8648eb Andrea Spadaccini
                vg_name=None, beparams=None, nicparams=None, ndparams=None,
524 bc5d0215 Andrea Spadaccini
                hvparams=None, diskparams=None, enabled_hypervisors=None,
525 bc5d0215 Andrea Spadaccini
                modify_etc_hosts=True, modify_ssh_setup=True,
526 bc5d0215 Andrea Spadaccini
                maintain_node_health=False, drbd_helper=None, uid_pool=None,
527 0359e5d0 Spyros Trigazis
                default_iallocator=None, default_iallocator_params=None,
528 0359e5d0 Spyros Trigazis
                primary_ip_version=None, ipolicy=None,
529 c4929a8b Renรฉ Nussbaumer
                prealloc_wipe_disks=False, use_external_mip_script=False,
530 3bde79ee Helga Velroyen
                hv_state=None, disk_state=None, enabled_disk_templates=None):
531 a0c9f010 Michael Hanselmann
  """Initialise the cluster.
532 a0c9f010 Michael Hanselmann

533 ce735215 Guido Trotter
  @type candidate_pool_size: int
534 ce735215 Guido Trotter
  @param candidate_pool_size: master candidate pool size
535 3bde79ee Helga Velroyen
  @type enabled_disk_templates: list of string
536 3bde79ee Helga Velroyen
  @param enabled_disk_templates: list of disk_templates to be used in this
537 c074a9e8 Helga Velroyen
    cluster
538 ce735215 Guido Trotter

539 a0c9f010 Michael Hanselmann
  """
540 ce735215 Guido Trotter
  # TODO: complete the docstring
541 a0c9f010 Michael Hanselmann
  if config.ConfigWriter.IsCluster():
542 debac808 Iustin Pop
    raise errors.OpPrereqError("Cluster is already initialised",
543 debac808 Iustin Pop
                               errors.ECODE_STATE)
544 a0c9f010 Michael Hanselmann
545 b119bccb Guido Trotter
  if not enabled_hypervisors:
546 b119bccb Guido Trotter
    raise errors.OpPrereqError("Enabled hypervisors list must contain at"
547 debac808 Iustin Pop
                               " least one member", errors.ECODE_INVAL)
548 b119bccb Guido Trotter
  invalid_hvs = set(enabled_hypervisors) - constants.HYPER_TYPES
549 b119bccb Guido Trotter
  if invalid_hvs:
550 b119bccb Guido Trotter
    raise errors.OpPrereqError("Enabled hypervisors contains invalid"
551 debac808 Iustin Pop
                               " entries: %s" % invalid_hvs,
552 debac808 Iustin Pop
                               errors.ECODE_INVAL)
553 b119bccb Guido Trotter
554 5030cff3 Helga Velroyen
  _InitCheckEnabledDiskTemplates(enabled_disk_templates)
555 c074a9e8 Helga Velroyen
556 5a8648eb Andrea Spadaccini
  try:
557 5a8648eb Andrea Spadaccini
    ipcls = netutils.IPAddress.GetClassFromIpVersion(primary_ip_version)
558 5a8648eb Andrea Spadaccini
  except errors.ProgrammerError:
559 2f20d07b Manuel Franceschini
    raise errors.OpPrereqError("Invalid primary ip version: %d." %
560 2cfbc784 Iustin Pop
                               primary_ip_version, errors.ECODE_INVAL)
561 2f20d07b Manuel Franceschini
562 2f20d07b Manuel Franceschini
  hostname = netutils.GetHostname(family=ipcls.family)
563 2f20d07b Manuel Franceschini
  if not ipcls.IsValid(hostname.ip):
564 2f20d07b Manuel Franceschini
    raise errors.OpPrereqError("This host's IP (%s) is not a valid IPv%d"
565 2cfbc784 Iustin Pop
                               " address." % (hostname.ip, primary_ip_version),
566 2cfbc784 Iustin Pop
                               errors.ECODE_INVAL)
567 2f20d07b Manuel Franceschini
568 2f20d07b Manuel Franceschini
  if ipcls.IsLoopback(hostname.ip):
569 8b312c1d Manuel Franceschini
    raise errors.OpPrereqError("This host's IP (%s) resolves to a loopback"
570 8b312c1d Manuel Franceschini
                               " address. Please fix DNS or %s." %
571 ee045466 Michael Hanselmann
                               (hostname.ip, pathutils.ETC_HOSTS),
572 debac808 Iustin Pop
                               errors.ECODE_ENVIRON)
573 a0c9f010 Michael Hanselmann
574 2f20d07b Manuel Franceschini
  if not ipcls.Own(hostname.ip):
575 a0c9f010 Michael Hanselmann
    raise errors.OpPrereqError("Inconsistency: this host's name resolves"
576 a0c9f010 Michael Hanselmann
                               " to %s,\nbut this ip address does not"
577 7c4c22f5 Manuel Franceschini
                               " belong to this host" %
578 debac808 Iustin Pop
                               hostname.ip, errors.ECODE_ENVIRON)
579 a0c9f010 Michael Hanselmann
580 2f20d07b Manuel Franceschini
  clustername = netutils.GetHostname(name=cluster_name, family=ipcls.family)
581 a0c9f010 Michael Hanselmann
582 2f20d07b Manuel Franceschini
  if netutils.TcpPing(clustername.ip, constants.DEFAULT_NODED_PORT, timeout=5):
583 7c4c22f5 Manuel Franceschini
    raise errors.OpPrereqError("Cluster IP already active",
584 debac808 Iustin Pop
                               errors.ECODE_NOTUNIQUE)
585 a0c9f010 Michael Hanselmann
586 2f20d07b Manuel Franceschini
  if not secondary_ip:
587 2f20d07b Manuel Franceschini
    if primary_ip_version == constants.IP6_VERSION:
588 2f20d07b Manuel Franceschini
      raise errors.OpPrereqError("When using a IPv6 primary address, a valid"
589 7c4c22f5 Manuel Franceschini
                                 " IPv4 address must be given as secondary",
590 7c4c22f5 Manuel Franceschini
                                 errors.ECODE_INVAL)
591 b9eeeb02 Michael Hanselmann
    secondary_ip = hostname.ip
592 a0c9f010 Michael Hanselmann
593 2f20d07b Manuel Franceschini
  if not netutils.IP4Address.IsValid(secondary_ip):
594 2f20d07b Manuel Franceschini
    raise errors.OpPrereqError("Secondary IP address (%s) has to be a valid"
595 2f20d07b Manuel Franceschini
                               " IPv4 address." % secondary_ip,
596 2f20d07b Manuel Franceschini
                               errors.ECODE_INVAL)
597 2f20d07b Manuel Franceschini
598 2f20d07b Manuel Franceschini
  if not netutils.IP4Address.Own(secondary_ip):
599 2f20d07b Manuel Franceschini
    raise errors.OpPrereqError("You gave %s as secondary IP,"
600 2f20d07b Manuel Franceschini
                               " but it does not belong to this host." %
601 2f20d07b Manuel Franceschini
                               secondary_ip, errors.ECODE_ENVIRON)
602 2f20d07b Manuel Franceschini
603 5a8648eb Andrea Spadaccini
  if master_netmask is not None:
604 5a8648eb Andrea Spadaccini
    if not ipcls.ValidateNetmask(master_netmask):
605 5a8648eb Andrea Spadaccini
      raise errors.OpPrereqError("CIDR netmask (%s) not valid for IPv%s " %
606 2cfbc784 Iustin Pop
                                  (master_netmask, primary_ip_version),
607 2cfbc784 Iustin Pop
                                 errors.ECODE_INVAL)
608 5a8648eb Andrea Spadaccini
  else:
609 5a8648eb Andrea Spadaccini
    master_netmask = ipcls.iplen
610 5a8648eb Andrea Spadaccini
611 912737ba Helga Velroyen
  if vg_name:
612 a0c9f010 Michael Hanselmann
    # Check if volume group is valid
613 a0c9f010 Michael Hanselmann
    vgstatus = utils.CheckVolumeGroupSize(utils.ListVolumeGroups(), vg_name,
614 a0c9f010 Michael Hanselmann
                                          constants.MIN_VG_SIZE)
615 a0c9f010 Michael Hanselmann
    if vgstatus:
616 912737ba Helga Velroyen
      raise errors.OpPrereqError("Error: %s" % vgstatus, errors.ECODE_INVAL)
617 a0c9f010 Michael Hanselmann
618 7796e1f8 Helga Velroyen
  drbd_enabled = constants.DT_DRBD8 in enabled_disk_templates
619 7796e1f8 Helga Velroyen
  _InitCheckDrbdHelper(drbd_helper, drbd_enabled)
620 a721e23a Luca Bigliardi
621 32ba31be Michael Hanselmann
  logging.debug("Stopping daemons (if any are running)")
622 32ba31be Michael Hanselmann
  result = utils.RunCmd([pathutils.DAEMON_UTIL, "stop-all"])
623 32ba31be Michael Hanselmann
  if result.failed:
624 32ba31be Michael Hanselmann
    raise errors.OpExecError("Could not stop daemons, command %s"
625 32ba31be Michael Hanselmann
                             " had exitcode %s and error '%s'" %
626 32ba31be Michael Hanselmann
                             (result.cmd, result.exit_code, result.output))
627 32ba31be Michael Hanselmann
628 5030cff3 Helga Velroyen
  file_storage_dir = _PrepareFileStorage(enabled_disk_templates,
629 5030cff3 Helga Velroyen
                                         file_storage_dir)
630 e8b5640e Helga Velroyen
  shared_file_storage_dir = _PrepareSharedFileStorage(enabled_disk_templates,
631 e8b5640e Helga Velroyen
                                                      shared_file_storage_dir)
632 a0c9f010 Michael Hanselmann
633 a0c9f010 Michael Hanselmann
  if not re.match("^[0-9a-z]{2}:[0-9a-z]{2}:[0-9a-z]{2}$", mac_prefix):
634 debac808 Iustin Pop
    raise errors.OpPrereqError("Invalid mac prefix given '%s'" % mac_prefix,
635 debac808 Iustin Pop
                               errors.ECODE_INVAL)
636 a0c9f010 Michael Hanselmann
637 dfc3afd9 Thomas Thrainer
  if not nicparams.get('mode', None) == constants.NIC_MODE_OVS:
638 d5e9de7c Sebastian Gebhard
    # Do not do this check if mode=openvswitch, since the openvswitch is not
639 d5e9de7c Sebastian Gebhard
    # created yet
640 d5e9de7c Sebastian Gebhard
    result = utils.RunCmd(["ip", "link", "show", "dev", master_netdev])
641 d5e9de7c Sebastian Gebhard
    if result.failed:
642 d5e9de7c Sebastian Gebhard
      raise errors.OpPrereqError("Invalid master netdev given (%s): '%s'" %
643 d5e9de7c Sebastian Gebhard
                                 (master_netdev,
644 d5e9de7c Sebastian Gebhard
                                  result.output.strip()), errors.ECODE_INVAL)
645 a0c9f010 Michael Hanselmann
646 7ede9c6a Michael Hanselmann
  dirs = [(pathutils.RUN_DIR, constants.RUN_DIRS_MODE)]
647 9dae41ad Guido Trotter
  utils.EnsureDirs(dirs)
648 9dae41ad Guido Trotter
649 b2e233a5 Guido Trotter
  objects.UpgradeBeParams(beparams)
650 a5728081 Guido Trotter
  utils.ForceDictType(beparams, constants.BES_PARAMETER_TYPES)
651 b6a30b0d Guido Trotter
  utils.ForceDictType(nicparams, constants.NICS_PARAMETER_TYPES)
652 18bb6d28 Agata Murawska
653 b6a30b0d Guido Trotter
  objects.NIC.CheckParameterSyntax(nicparams)
654 57dc299a Iustin Pop
655 2cc673a3 Iustin Pop
  full_ipolicy = objects.FillIPolicy(constants.IPOLICY_DEFAULTS, ipolicy)
656 d514e18b Helga Velroyen
  _RestrictIpolicyToEnabledDiskTemplates(full_ipolicy, enabled_disk_templates)
657 b6a30b0d Guido Trotter
658 6204ee71 Renรฉ Nussbaumer
  if ndparams is not None:
659 6204ee71 Renรฉ Nussbaumer
    utils.ForceDictType(ndparams, constants.NDS_PARAMETER_TYPES)
660 6204ee71 Renรฉ Nussbaumer
  else:
661 6204ee71 Renรฉ Nussbaumer
    ndparams = dict(constants.NDC_DEFAULTS)
662 6204ee71 Renรฉ Nussbaumer
663 c4929a8b Renรฉ Nussbaumer
  # This is ugly, as we modify the dict itself
664 57dc299a Iustin Pop
  # FIXME: Make utils.ForceDictType pure functional or write a wrapper
665 57dc299a Iustin Pop
  # around it
666 c4929a8b Renรฉ Nussbaumer
  if hv_state:
667 c4929a8b Renรฉ Nussbaumer
    for hvname, hvs_data in hv_state.items():
668 c4929a8b Renรฉ Nussbaumer
      utils.ForceDictType(hvs_data, constants.HVSTS_PARAMETER_TYPES)
669 c4929a8b Renรฉ Nussbaumer
      hv_state[hvname] = objects.Cluster.SimpleFillHvState(hvs_data)
670 c4929a8b Renรฉ Nussbaumer
  else:
671 c4929a8b Renรฉ Nussbaumer
    hv_state = dict((hvname, constants.HVST_DEFAULTS)
672 c4929a8b Renรฉ Nussbaumer
                    for hvname in enabled_hypervisors)
673 c4929a8b Renรฉ Nussbaumer
674 c4929a8b Renรฉ Nussbaumer
  # FIXME: disk_state has no default values yet
675 c4929a8b Renรฉ Nussbaumer
  if disk_state:
676 c4929a8b Renรฉ Nussbaumer
    for storage, ds_data in disk_state.items():
677 c4929a8b Renรฉ Nussbaumer
      if storage not in constants.DS_VALID_TYPES:
678 c4929a8b Renรฉ Nussbaumer
        raise errors.OpPrereqError("Invalid storage type in disk state: %s" %
679 c4929a8b Renรฉ Nussbaumer
                                   storage, errors.ECODE_INVAL)
680 c4929a8b Renรฉ Nussbaumer
      for ds_name, state in ds_data.items():
681 c4929a8b Renรฉ Nussbaumer
        utils.ForceDictType(state, constants.DSS_PARAMETER_TYPES)
682 c4929a8b Renรฉ Nussbaumer
        ds_data[ds_name] = objects.Cluster.SimpleFillDiskState(state)
683 c4929a8b Renรฉ Nussbaumer
684 a5728081 Guido Trotter
  # hvparams is a mapping of hypervisor->hvparams dict
685 a5728081 Guido Trotter
  for hv_name, hv_params in hvparams.iteritems():
686 a5728081 Guido Trotter
    utils.ForceDictType(hv_params, constants.HVS_PARAMETER_TYPES)
687 a5728081 Guido Trotter
    hv_class = hypervisor.GetHypervisor(hv_name)
688 a5728081 Guido Trotter
    hv_class.CheckParameterSyntax(hv_params)
689 d4b72030 Guido Trotter
690 bc5d0215 Andrea Spadaccini
  # diskparams is a mapping of disk-template->diskparams dict
691 bc5d0215 Andrea Spadaccini
  for template, dt_params in diskparams.items():
692 bc5d0215 Andrea Spadaccini
    param_keys = set(dt_params.keys())
693 bc5d0215 Andrea Spadaccini
    default_param_keys = set(constants.DISK_DT_DEFAULTS[template].keys())
694 bc5d0215 Andrea Spadaccini
    if not (param_keys <= default_param_keys):
695 bc5d0215 Andrea Spadaccini
      unknown_params = param_keys - default_param_keys
696 bc5d0215 Andrea Spadaccini
      raise errors.OpPrereqError("Invalid parameters for disk template %s:"
697 bc5d0215 Andrea Spadaccini
                                 " %s" % (template,
698 2cfbc784 Iustin Pop
                                          utils.CommaJoin(unknown_params)),
699 2cfbc784 Iustin Pop
                                 errors.ECODE_INVAL)
700 bc5d0215 Andrea Spadaccini
    utils.ForceDictType(dt_params, constants.DISK_DT_TYPES)
701 35c48839 Michele Tartara
    if template == constants.DT_DRBD8 and vg_name is not None:
702 35c48839 Michele Tartara
      # The default METAVG value is equal to the VG name set at init time,
703 35c48839 Michele Tartara
      # if provided
704 35c48839 Michele Tartara
      dt_params[constants.DRBD_DEFAULT_METAVG] = vg_name
705 35c48839 Michele Tartara
706 e4a4391d Renรฉ Nussbaumer
  try:
707 e4a4391d Renรฉ Nussbaumer
    utils.VerifyDictOptions(diskparams, constants.DISK_DT_DEFAULTS)
708 e4a4391d Renรฉ Nussbaumer
  except errors.OpPrereqError, err:
709 e4a4391d Renรฉ Nussbaumer
    raise errors.OpPrereqError("While verify diskparam options: %s" % err,
710 e4a4391d Renรฉ Nussbaumer
                               errors.ECODE_INVAL)
711 bc5d0215 Andrea Spadaccini
712 a0c9f010 Michael Hanselmann
  # set up ssh config and /etc/hosts
713 a9542a4f Thomas Thrainer
  rsa_sshkey = ""
714 a9542a4f Thomas Thrainer
  dsa_sshkey = ""
715 a9542a4f Thomas Thrainer
  if os.path.isfile(pathutils.SSH_HOST_RSA_PUB):
716 a9542a4f Thomas Thrainer
    sshline = utils.ReadFile(pathutils.SSH_HOST_RSA_PUB)
717 a9542a4f Thomas Thrainer
    rsa_sshkey = sshline.split(" ")[1]
718 a9542a4f Thomas Thrainer
  if os.path.isfile(pathutils.SSH_HOST_DSA_PUB):
719 a9542a4f Thomas Thrainer
    sshline = utils.ReadFile(pathutils.SSH_HOST_DSA_PUB)
720 a9542a4f Thomas Thrainer
    dsa_sshkey = sshline.split(" ")[1]
721 a9542a4f Thomas Thrainer
  if not rsa_sshkey and not dsa_sshkey:
722 a9542a4f Thomas Thrainer
    raise errors.OpPrereqError("Failed to find SSH public keys",
723 a9542a4f Thomas Thrainer
                               errors.ECODE_ENVIRON)
724 a0c9f010 Michael Hanselmann
725 b86a6bcd Guido Trotter
  if modify_etc_hosts:
726 ea8ac9c9 Renรฉ Nussbaumer
    utils.AddHostToEtcHosts(hostname.name, hostname.ip)
727 b86a6bcd Guido Trotter
728 b989b9d9 Ken Wehr
  if modify_ssh_setup:
729 b989b9d9 Ken Wehr
    _InitSSHSetup()
730 a0c9f010 Michael Hanselmann
731 bf4af505 Apollon Oikonomopoulos
  if default_iallocator is not None:
732 bf4af505 Apollon Oikonomopoulos
    alloc_script = utils.FindFile(default_iallocator,
733 bf4af505 Apollon Oikonomopoulos
                                  constants.IALLOCATOR_SEARCH_PATH,
734 bf4af505 Apollon Oikonomopoulos
                                  os.path.isfile)
735 bf4af505 Apollon Oikonomopoulos
    if alloc_script is None:
736 bf4af505 Apollon Oikonomopoulos
      raise errors.OpPrereqError("Invalid default iallocator script '%s'"
737 bf4af505 Apollon Oikonomopoulos
                                 " specified" % default_iallocator,
738 bf4af505 Apollon Oikonomopoulos
                                 errors.ECODE_INVAL)
739 0cd5ab45 Petr Pudlak
  else:
740 0cd5ab45 Petr Pudlak
    # default to htools
741 d1e9c98d Iustin Pop
    if utils.FindFile(constants.IALLOC_HAIL,
742 d1e9c98d Iustin Pop
                      constants.IALLOCATOR_SEARCH_PATH,
743 d1e9c98d Iustin Pop
                      os.path.isfile):
744 d1e9c98d Iustin Pop
      default_iallocator = constants.IALLOC_HAIL
745 bf4af505 Apollon Oikonomopoulos
746 9cdea43f Petr Pudlak
  # check if we have all the users we need
747 9cdea43f Petr Pudlak
  try:
748 9cdea43f Petr Pudlak
    runtime.GetEnts()
749 9cdea43f Petr Pudlak
  except errors.ConfigurationError, err:
750 9cdea43f Petr Pudlak
    raise errors.OpPrereqError("Required system user/group missing: %s" %
751 9cdea43f Petr Pudlak
                               err, errors.ECODE_ENVIRON)
752 9cdea43f Petr Pudlak
753 3bcf2140 Helga Velroyen
  candidate_certs = {}
754 3bcf2140 Helga Velroyen
755 430b923c Iustin Pop
  now = time.time()
756 430b923c Iustin Pop
757 a0c9f010 Michael Hanselmann
  # init of cluster config file
758 b9eeeb02 Michael Hanselmann
  cluster_config = objects.Cluster(
759 b9eeeb02 Michael Hanselmann
    serial_no=1,
760 a9542a4f Thomas Thrainer
    rsahostkeypub=rsa_sshkey,
761 a9542a4f Thomas Thrainer
    dsahostkeypub=dsa_sshkey,
762 b9eeeb02 Michael Hanselmann
    highest_used_port=(constants.FIRST_DRBD_PORT - 1),
763 b9eeeb02 Michael Hanselmann
    mac_prefix=mac_prefix,
764 b9eeeb02 Michael Hanselmann
    volume_group_name=vg_name,
765 b9eeeb02 Michael Hanselmann
    tcpudp_port_pool=set(),
766 f6bd6e98 Michael Hanselmann
    master_ip=clustername.ip,
767 5a8648eb Andrea Spadaccini
    master_netmask=master_netmask,
768 f6bd6e98 Michael Hanselmann
    master_netdev=master_netdev,
769 f6bd6e98 Michael Hanselmann
    cluster_name=clustername.name,
770 f6bd6e98 Michael Hanselmann
    file_storage_dir=file_storage_dir,
771 4b97f902 Apollon Oikonomopoulos
    shared_file_storage_dir=shared_file_storage_dir,
772 d3e6fd0e Santi Raffa
    gluster_storage_dir=gluster_storage_dir,
773 ea3a925f Alexander Schreiber
    enabled_hypervisors=enabled_hypervisors,
774 4ef7f423 Guido Trotter
    beparams={constants.PP_DEFAULT: beparams},
775 b6a30b0d Guido Trotter
    nicparams={constants.PP_DEFAULT: nicparams},
776 6204ee71 Renรฉ Nussbaumer
    ndparams=ndparams,
777 ea3a925f Alexander Schreiber
    hvparams=hvparams,
778 bc5d0215 Andrea Spadaccini
    diskparams=diskparams,
779 ce735215 Guido Trotter
    candidate_pool_size=candidate_pool_size,
780 022c3a0b Guido Trotter
    modify_etc_hosts=modify_etc_hosts,
781 b989b9d9 Ken Wehr
    modify_ssh_setup=modify_ssh_setup,
782 39b0f0c2 Balazs Lecz
    uid_pool=uid_pool,
783 430b923c Iustin Pop
    ctime=now,
784 430b923c Iustin Pop
    mtime=now,
785 3953242f Iustin Pop
    maintain_node_health=maintain_node_health,
786 a721e23a Luca Bigliardi
    drbd_usermode_helper=drbd_helper,
787 bf4af505 Apollon Oikonomopoulos
    default_iallocator=default_iallocator,
788 0359e5d0 Spyros Trigazis
    default_iallocator_params=default_iallocator_params,
789 2f20d07b Manuel Franceschini
    primary_ip_family=ipcls.family,
790 3d914585 Renรฉ Nussbaumer
    prealloc_wipe_disks=prealloc_wipe_disks,
791 bf689b7a Andrea Spadaccini
    use_external_mip_script=use_external_mip_script,
792 57dc299a Iustin Pop
    ipolicy=full_ipolicy,
793 c4929a8b Renรฉ Nussbaumer
    hv_state_static=hv_state,
794 c4929a8b Renรฉ Nussbaumer
    disk_state_static=disk_state,
795 3bde79ee Helga Velroyen
    enabled_disk_templates=enabled_disk_templates,
796 3bcf2140 Helga Velroyen
    candidate_certs=candidate_certs,
797 a5efec93 Santi Raffa
    osparams={},
798 a5efec93 Santi Raffa
    osparams_private_cluster={}
799 b9eeeb02 Michael Hanselmann
    )
800 b9eeeb02 Michael Hanselmann
  master_node_config = objects.Node(name=hostname.name,
801 b9eeeb02 Michael Hanselmann
                                    primary_ip=hostname.ip,
802 b9222f32 Guido Trotter
                                    secondary_ip=secondary_ip,
803 c044f32c Guido Trotter
                                    serial_no=1,
804 c044f32c Guido Trotter
                                    master_candidate=True,
805 af64c0ea Iustin Pop
                                    offline=False, drained=False,
806 435e4bd6 Michael Hanselmann
                                    ctime=now, mtime=now,
807 c044f32c Guido Trotter
                                    )
808 9e1333b9 Guido Trotter
  InitConfig(constants.CONFIG_VERSION, cluster_config, master_node_config)
809 d367b66c Manuel Franceschini
  cfg = config.ConfigWriter(offline=True)
810 7ede9c6a Michael Hanselmann
  ssh.WriteKnownHostsFile(cfg, pathutils.SSH_KNOWN_HOSTS_FILE)
811 a4eae71f Michael Hanselmann
  cfg.Update(cfg.GetClusterInfo(), logging.error)
812 ee501db1 Michael Hanselmann
  ssconf.WriteSsconfFiles(cfg.GetSsconfValues())
813 d367b66c Manuel Franceschini
814 d367b66c Manuel Franceschini
  # set up the inter-node password and certificate
815 d367b66c Manuel Franceschini
  _InitGanetiServerSetup(hostname.name)
816 827f753e Guido Trotter
817 952d7515 Michael Hanselmann
  logging.debug("Starting daemons")
818 7ede9c6a Michael Hanselmann
  result = utils.RunCmd([pathutils.DAEMON_UTIL, "start-all"])
819 952d7515 Michael Hanselmann
  if result.failed:
820 952d7515 Michael Hanselmann
    raise errors.OpExecError("Could not start daemons, command %s"
821 952d7515 Michael Hanselmann
                             " had exitcode %s and error %s" %
822 952d7515 Michael Hanselmann
                             (result.cmd, result.exit_code, result.output))
823 b3f1cf6f Iustin Pop
824 3b6b6129 Michael Hanselmann
  _WaitForMasterDaemon()
825 b3f1cf6f Iustin Pop
826 b1b6ea87 Iustin Pop
827 02f99608 Oleksiy Mishchenko
def InitConfig(version, cluster_config, master_node_config,
828 7ede9c6a Michael Hanselmann
               cfg_file=pathutils.CLUSTER_CONF_FILE):
829 7b3a8fb5 Iustin Pop
  """Create the initial cluster configuration.
830 7b3a8fb5 Iustin Pop

831 7b3a8fb5 Iustin Pop
  It will contain the current node, which will also be the master
832 7b3a8fb5 Iustin Pop
  node, and no instances.
833 7b3a8fb5 Iustin Pop

834 7b3a8fb5 Iustin Pop
  @type version: int
835 c41eea6e Iustin Pop
  @param version: configuration version
836 c41eea6e Iustin Pop
  @type cluster_config: L{objects.Cluster}
837 c41eea6e Iustin Pop
  @param cluster_config: cluster configuration
838 c41eea6e Iustin Pop
  @type master_node_config: L{objects.Node}
839 c41eea6e Iustin Pop
  @param master_node_config: master node configuration
840 c41eea6e Iustin Pop
  @type cfg_file: string
841 c41eea6e Iustin Pop
  @param cfg_file: configuration file path
842 c41eea6e Iustin Pop

843 7b3a8fb5 Iustin Pop
  """
844 88b92fe3 Guido Trotter
  uuid_generator = config.TemporaryReservationManager()
845 88b92fe3 Guido Trotter
  cluster_config.uuid = uuid_generator.Generate([], utils.NewUUID,
846 88b92fe3 Guido Trotter
                                                _INITCONF_ECID)
847 88b92fe3 Guido Trotter
  master_node_config.uuid = uuid_generator.Generate([], utils.NewUUID,
848 88b92fe3 Guido Trotter
                                                    _INITCONF_ECID)
849 1c3231aa Thomas Thrainer
  cluster_config.master_node = master_node_config.uuid
850 7b3a8fb5 Iustin Pop
  nodes = {
851 1c3231aa Thomas Thrainer
    master_node_config.uuid: master_node_config,
852 7b3a8fb5 Iustin Pop
    }
853 88b92fe3 Guido Trotter
  default_nodegroup = objects.NodeGroup(
854 88b92fe3 Guido Trotter
    uuid=uuid_generator.Generate([], utils.NewUUID, _INITCONF_ECID),
855 75cf411a Adeodato Simo
    name=constants.INITIAL_NODE_GROUP_NAME,
856 1c3231aa Thomas Thrainer
    members=[master_node_config.uuid],
857 99ccf8b9 Renรฉ Nussbaumer
    diskparams={},
858 88b92fe3 Guido Trotter
    )
859 88b92fe3 Guido Trotter
  nodegroups = {
860 88b92fe3 Guido Trotter
    default_nodegroup.uuid: default_nodegroup,
861 88b92fe3 Guido Trotter
    }
862 d693c864 Iustin Pop
  now = time.time()
863 7b3a8fb5 Iustin Pop
  config_data = objects.ConfigData(version=version,
864 7b3a8fb5 Iustin Pop
                                   cluster=cluster_config,
865 88b92fe3 Guido Trotter
                                   nodegroups=nodegroups,
866 7b3a8fb5 Iustin Pop
                                   nodes=nodes,
867 7b3a8fb5 Iustin Pop
                                   instances={},
868 eaa4c57c Dimitris Aragiorgis
                                   networks={},
869 d693c864 Iustin Pop
                                   serial_no=1,
870 d693c864 Iustin Pop
                                   ctime=now, mtime=now)
871 a33848a5 Guido Trotter
  utils.WriteFile(cfg_file,
872 a33848a5 Guido Trotter
                  data=serializer.Dump(config_data.ToDict()),
873 a33848a5 Guido Trotter
                  mode=0600)
874 02f99608 Oleksiy Mishchenko
875 02f99608 Oleksiy Mishchenko
876 1c3231aa Thomas Thrainer
def FinalizeClusterDestroy(master_uuid):
877 140aa4a8 Iustin Pop
  """Execute the last steps of cluster destroy
878 140aa4a8 Iustin Pop

879 140aa4a8 Iustin Pop
  This function shuts down all the daemons, completing the destroy
880 140aa4a8 Iustin Pop
  begun in cmdlib.LUDestroyOpcode.
881 140aa4a8 Iustin Pop

882 140aa4a8 Iustin Pop
  """
883 b989b9d9 Ken Wehr
  cfg = config.ConfigWriter()
884 b989b9d9 Ken Wehr
  modify_ssh_setup = cfg.GetClusterInfo().modify_ssh_setup
885 7c74bbe0 Andrea Spadaccini
  runner = rpc.BootstrapRunner()
886 7c74bbe0 Andrea Spadaccini
887 1c3231aa Thomas Thrainer
  master_name = cfg.GetNodeName(master_uuid)
888 1c3231aa Thomas Thrainer
889 f9d20654 Andrea Spadaccini
  master_params = cfg.GetMasterNetworkParameters()
890 1c3231aa Thomas Thrainer
  master_params.uuid = master_uuid
891 57c7bc57 Andrea Spadaccini
  ems = cfg.GetUseExternalMipScript()
892 1c3231aa Thomas Thrainer
  result = runner.call_node_deactivate_master_ip(master_name, master_params,
893 1c3231aa Thomas Thrainer
                                                 ems)
894 c79198a0 Andrea Spadaccini
895 7c74bbe0 Andrea Spadaccini
  msg = result.fail_msg
896 7c74bbe0 Andrea Spadaccini
  if msg:
897 7c74bbe0 Andrea Spadaccini
    logging.warning("Could not disable the master IP: %s", msg)
898 7c74bbe0 Andrea Spadaccini
899 1c3231aa Thomas Thrainer
  result = runner.call_node_stop_master(master_name)
900 3cebe102 Michael Hanselmann
  msg = result.fail_msg
901 6c00d19a Iustin Pop
  if msg:
902 099c52ad Iustin Pop
    logging.warning("Could not disable the master role: %s", msg)
903 7c74bbe0 Andrea Spadaccini
904 1c3231aa Thomas Thrainer
  result = runner.call_node_leave_cluster(master_name, modify_ssh_setup)
905 3cebe102 Michael Hanselmann
  msg = result.fail_msg
906 0623d351 Iustin Pop
  if msg:
907 0623d351 Iustin Pop
    logging.warning("Could not shutdown the node daemon and cleanup"
908 0623d351 Iustin Pop
                    " the node: %s", msg)
909 140aa4a8 Iustin Pop
910 140aa4a8 Iustin Pop
911 a9f33339 Petr Pudlak
def SetupNodeDaemon(opts, cluster_name, node, ssh_port):
912 827f753e Guido Trotter
  """Add a node to the cluster.
913 827f753e Guido Trotter

914 b1b6ea87 Iustin Pop
  This function must be called before the actual opcode, and will ssh
915 b1b6ea87 Iustin Pop
  to the remote node, copy the needed files, and start ganeti-noded,
916 b1b6ea87 Iustin Pop
  allowing the master to do the rest via normal rpc calls.
917 827f753e Guido Trotter

918 87622829 Iustin Pop
  @param cluster_name: the cluster name
919 87622829 Iustin Pop
  @param node: the name of the new node
920 a9f33339 Petr Pudlak
  @param ssh_port: the SSH port of the new node
921 827f753e Guido Trotter

922 827f753e Guido Trotter
  """
923 7b8ba235 Michael Hanselmann
  data = {
924 7b8ba235 Michael Hanselmann
    constants.NDS_CLUSTER_NAME: cluster_name,
925 7b8ba235 Michael Hanselmann
    constants.NDS_NODE_DAEMON_CERTIFICATE:
926 7b8ba235 Michael Hanselmann
      utils.ReadFile(pathutils.NODED_CERT_FILE),
927 7b8ba235 Michael Hanselmann
    constants.NDS_SSCONF: ssconf.SimpleStore().ReadAll(),
928 7b8ba235 Michael Hanselmann
    constants.NDS_START_NODE_DAEMON: True,
929 7b8ba235 Michael Hanselmann
    }
930 7b8ba235 Michael Hanselmann
931 7b8ba235 Michael Hanselmann
  RunNodeSetupCmd(cluster_name, node, pathutils.NODE_DAEMON_SETUP,
932 7b8ba235 Michael Hanselmann
                  opts.debug, opts.verbose,
933 a9f33339 Petr Pudlak
                  True, opts.ssh_key_check, opts.ssh_key_check,
934 a9f33339 Petr Pudlak
                  ssh_port, data)
935 827f753e Guido Trotter
936 5627f375 Michael Hanselmann
  _WaitForNodeDaemon(node)
937 5627f375 Michael Hanselmann
938 b1b6ea87 Iustin Pop
939 8e2524c3 Guido Trotter
def MasterFailover(no_voting=False):
940 b1b6ea87 Iustin Pop
  """Failover the master node.
941 b1b6ea87 Iustin Pop

942 b1b6ea87 Iustin Pop
  This checks that we are not already the master, and will cause the
943 b1b6ea87 Iustin Pop
  current master to cease being master, and the non-master to become
944 b1b6ea87 Iustin Pop
  new master.
945 b1b6ea87 Iustin Pop

946 8e2524c3 Guido Trotter
  @type no_voting: boolean
947 8e2524c3 Guido Trotter
  @param no_voting: force the operation without remote nodes agreement
948 8e2524c3 Guido Trotter
                      (dangerous)
949 8e2524c3 Guido Trotter

950 b1b6ea87 Iustin Pop
  """
951 8135a2db Iustin Pop
  sstore = ssconf.SimpleStore()
952 b1b6ea87 Iustin Pop
953 8135a2db Iustin Pop
  old_master, new_master = ssconf.GetMasterAndMyself(sstore)
954 1c3231aa Thomas Thrainer
  node_names = sstore.GetNodeList()
955 8135a2db Iustin Pop
  mc_list = sstore.GetMasterCandidates()
956 b1b6ea87 Iustin Pop
957 b1b6ea87 Iustin Pop
  if old_master == new_master:
958 b1b6ea87 Iustin Pop
    raise errors.OpPrereqError("This commands must be run on the node"
959 b1b6ea87 Iustin Pop
                               " where you want the new master to be."
960 b1b6ea87 Iustin Pop
                               " %s is already the master" %
961 debac808 Iustin Pop
                               old_master, errors.ECODE_INVAL)
962 d5927e48 Iustin Pop
963 8135a2db Iustin Pop
  if new_master not in mc_list:
964 8135a2db Iustin Pop
    mc_no_master = [name for name in mc_list if name != old_master]
965 8135a2db Iustin Pop
    raise errors.OpPrereqError("This node is not among the nodes marked"
966 8135a2db Iustin Pop
                               " as master candidates. Only these nodes"
967 8135a2db Iustin Pop
                               " can become masters. Current list of"
968 8135a2db Iustin Pop
                               " master candidates is:\n"
969 3ccb3a64 Michael Hanselmann
                               "%s" % ("\n".join(mc_no_master)),
970 debac808 Iustin Pop
                               errors.ECODE_STATE)
971 8135a2db Iustin Pop
972 8e2524c3 Guido Trotter
  if not no_voting:
973 1c3231aa Thomas Thrainer
    vote_list = GatherMasterVotes(node_names)
974 8e2524c3 Guido Trotter
975 8e2524c3 Guido Trotter
    if vote_list:
976 8e2524c3 Guido Trotter
      voted_master = vote_list[0][0]
977 8e2524c3 Guido Trotter
      if voted_master is None:
978 8e2524c3 Guido Trotter
        raise errors.OpPrereqError("Cluster is inconsistent, most nodes did"
979 debac808 Iustin Pop
                                   " not respond.", errors.ECODE_ENVIRON)
980 8e2524c3 Guido Trotter
      elif voted_master != old_master:
981 8e2524c3 Guido Trotter
        raise errors.OpPrereqError("I have a wrong configuration, I believe"
982 8e2524c3 Guido Trotter
                                   " the master is %s but the other nodes"
983 8e2524c3 Guido Trotter
                                   " voted %s. Please resync the configuration"
984 8e2524c3 Guido Trotter
                                   " of this node." %
985 debac808 Iustin Pop
                                   (old_master, voted_master),
986 debac808 Iustin Pop
                                   errors.ECODE_STATE)
987 b1b6ea87 Iustin Pop
  # end checks
988 b1b6ea87 Iustin Pop
989 b1b6ea87 Iustin Pop
  rcode = 0
990 b1b6ea87 Iustin Pop
991 d5927e48 Iustin Pop
  logging.info("Setting master to %s, old master: %s", new_master, old_master)
992 b1b6ea87 Iustin Pop
993 21004460 Iustin Pop
  try:
994 80a56f26 Petr Pudlak
    # Start WConfd so that we can access the configuration
995 80a56f26 Petr Pudlak
    result = utils.RunCmd([pathutils.DAEMON_UTIL,
996 80a56f26 Petr Pudlak
                           "start", constants.WCONFD, "--force-node"])
997 80a56f26 Petr Pudlak
    if result.failed:
998 80a56f26 Petr Pudlak
      raise errors.OpPrereqError("Could not start the configuration daemon,"
999 80a56f26 Petr Pudlak
                                 " command %s had exitcode %s and error %s" %
1000 80a56f26 Petr Pudlak
                                 (result.cmd, result.exit_code, result.output),
1001 80a56f26 Petr Pudlak
                                 errors.ECODE_NOENT)
1002 80a56f26 Petr Pudlak
1003 21004460 Iustin Pop
    # instantiate a real config writer, as we now know we have the
1004 21004460 Iustin Pop
    # configuration data
1005 eb180fe2 Iustin Pop
    cfg = config.ConfigWriter(accept_foreign=True)
1006 21004460 Iustin Pop
1007 1c3231aa Thomas Thrainer
    old_master_node = cfg.GetNodeInfoByName(old_master)
1008 1c3231aa Thomas Thrainer
    if old_master_node is None:
1009 1c3231aa Thomas Thrainer
      raise errors.OpPrereqError("Could not find old master node '%s' in"
1010 1c3231aa Thomas Thrainer
                                 " cluster configuration." % old_master,
1011 1c3231aa Thomas Thrainer
                                 errors.ECODE_NOENT)
1012 1c3231aa Thomas Thrainer
1013 21004460 Iustin Pop
    cluster_info = cfg.GetClusterInfo()
1014 1c3231aa Thomas Thrainer
    new_master_node = cfg.GetNodeInfoByName(new_master)
1015 1c3231aa Thomas Thrainer
    if new_master_node is None:
1016 1c3231aa Thomas Thrainer
      raise errors.OpPrereqError("Could not find new master node '%s' in"
1017 1c3231aa Thomas Thrainer
                                 " cluster configuration." % new_master,
1018 1c3231aa Thomas Thrainer
                                 errors.ECODE_NOENT)
1019 1c3231aa Thomas Thrainer
1020 1c3231aa Thomas Thrainer
    cluster_info.master_node = new_master_node.uuid
1021 21004460 Iustin Pop
    # this will also regenerate the ssconf files, since we updated the
1022 21004460 Iustin Pop
    # cluster info
1023 21004460 Iustin Pop
    cfg.Update(cluster_info, logging.error)
1024 21004460 Iustin Pop
  except errors.ConfigurationError, err:
1025 21004460 Iustin Pop
    logging.error("Error while trying to set the new master: %s",
1026 21004460 Iustin Pop
                  str(err))
1027 21004460 Iustin Pop
    return 1
1028 80a56f26 Petr Pudlak
  finally:
1029 80a56f26 Petr Pudlak
    # stop WConfd again:
1030 80a56f26 Petr Pudlak
    result = utils.RunCmd([pathutils.DAEMON_UTIL, "stop", constants.WCONFD])
1031 80a56f26 Petr Pudlak
    if result.failed:
1032 80a56f26 Petr Pudlak
      logging.error("Could not stop the configuration daemon,"
1033 80a56f26 Petr Pudlak
                    " command %s had exitcode %s and error %s",
1034 80a56f26 Petr Pudlak
                    result.cmd, result.exit_code, result.output)
1035 21004460 Iustin Pop
1036 21004460 Iustin Pop
  # if cfg.Update worked, then it means the old master daemon won't be
1037 21004460 Iustin Pop
  # able now to write its own config file (we rely on locking in both
1038 21004460 Iustin Pop
  # backend.UploadFile() and ConfigWriter._Write(); hence the next
1039 21004460 Iustin Pop
  # step is to kill the old master
1040 21004460 Iustin Pop
1041 21004460 Iustin Pop
  logging.info("Stopping the master daemon on node %s", old_master)
1042 21004460 Iustin Pop
1043 7c74bbe0 Andrea Spadaccini
  runner = rpc.BootstrapRunner()
1044 f9d20654 Andrea Spadaccini
  master_params = cfg.GetMasterNetworkParameters()
1045 1c3231aa Thomas Thrainer
  master_params.uuid = old_master_node.uuid
1046 57c7bc57 Andrea Spadaccini
  ems = cfg.GetUseExternalMipScript()
1047 1c3231aa Thomas Thrainer
  result = runner.call_node_deactivate_master_ip(old_master,
1048 57c7bc57 Andrea Spadaccini
                                                 master_params, ems)
1049 c79198a0 Andrea Spadaccini
1050 7c74bbe0 Andrea Spadaccini
  msg = result.fail_msg
1051 7c74bbe0 Andrea Spadaccini
  if msg:
1052 7c74bbe0 Andrea Spadaccini
    logging.warning("Could not disable the master IP: %s", msg)
1053 7c74bbe0 Andrea Spadaccini
1054 7c74bbe0 Andrea Spadaccini
  result = runner.call_node_stop_master(old_master)
1055 3cebe102 Michael Hanselmann
  msg = result.fail_msg
1056 6c00d19a Iustin Pop
  if msg:
1057 d5927e48 Iustin Pop
    logging.error("Could not disable the master role on the old master"
1058 5ae4945a Iustin Pop
                  " %s, please disable manually: %s", old_master, msg)
1059 b1b6ea87 Iustin Pop
1060 21004460 Iustin Pop
  logging.info("Checking master IP non-reachability...")
1061 21004460 Iustin Pop
1062 425f0f54 Iustin Pop
  master_ip = sstore.GetMasterIP()
1063 425f0f54 Iustin Pop
  total_timeout = 30
1064 e687ec01 Michael Hanselmann
1065 d23ef431 Michael Hanselmann
  # Here we have a phase where no master should be running
1066 425f0f54 Iustin Pop
  def _check_ip():
1067 a744b676 Manuel Franceschini
    if netutils.TcpPing(master_ip, constants.DEFAULT_NODED_PORT):
1068 425f0f54 Iustin Pop
      raise utils.RetryAgain()
1069 425f0f54 Iustin Pop
1070 425f0f54 Iustin Pop
  try:
1071 425f0f54 Iustin Pop
    utils.Retry(_check_ip, (1, 1.5, 5), total_timeout)
1072 425f0f54 Iustin Pop
  except utils.RetryTimeout:
1073 425f0f54 Iustin Pop
    logging.warning("The master IP is still reachable after %s seconds,"
1074 425f0f54 Iustin Pop
                    " continuing but activating the master on the current"
1075 425f0f54 Iustin Pop
                    " node will probably fail", total_timeout)
1076 b1b6ea87 Iustin Pop
1077 ff699aa9 Michael Hanselmann
  if jstore.CheckDrainFlag():
1078 ff699aa9 Michael Hanselmann
    logging.info("Undraining job queue")
1079 ff699aa9 Michael Hanselmann
    jstore.SetDrainFlag(False)
1080 ff699aa9 Michael Hanselmann
1081 21004460 Iustin Pop
  logging.info("Starting the master daemons on the new master")
1082 d5927e48 Iustin Pop
1083 db04ce5d Michael Hanselmann
  result = rpc.BootstrapRunner().call_node_start_master_daemons(new_master,
1084 db04ce5d Michael Hanselmann
                                                                no_voting)
1085 3cebe102 Michael Hanselmann
  msg = result.fail_msg
1086 b726aff0 Iustin Pop
  if msg:
1087 d5927e48 Iustin Pop
    logging.error("Could not start the master role on the new master"
1088 b726aff0 Iustin Pop
                  " %s, please check: %s", new_master, msg)
1089 b1b6ea87 Iustin Pop
    rcode = 1
1090 b1b6ea87 Iustin Pop
1091 21004460 Iustin Pop
  logging.info("Master failed over from %s to %s", old_master, new_master)
1092 b1b6ea87 Iustin Pop
  return rcode
1093 d7cdb55d Iustin Pop
1094 d7cdb55d Iustin Pop
1095 8eb148ae Iustin Pop
def GetMaster():
1096 8eb148ae Iustin Pop
  """Returns the current master node.
1097 8eb148ae Iustin Pop

1098 8eb148ae Iustin Pop
  This is a separate function in bootstrap since it's needed by
1099 8eb148ae Iustin Pop
  gnt-cluster, and instead of importing directly ssconf, it's better
1100 8eb148ae Iustin Pop
  to abstract it in bootstrap, where we do use ssconf in other
1101 8eb148ae Iustin Pop
  functions too.
1102 8eb148ae Iustin Pop

1103 8eb148ae Iustin Pop
  """
1104 8eb148ae Iustin Pop
  sstore = ssconf.SimpleStore()
1105 8eb148ae Iustin Pop
1106 8eb148ae Iustin Pop
  old_master, _ = ssconf.GetMasterAndMyself(sstore)
1107 8eb148ae Iustin Pop
1108 8eb148ae Iustin Pop
  return old_master
1109 8eb148ae Iustin Pop
1110 8eb148ae Iustin Pop
1111 1c3231aa Thomas Thrainer
def GatherMasterVotes(node_names):
1112 d7cdb55d Iustin Pop
  """Check the agreement on who is the master.
1113 d7cdb55d Iustin Pop

1114 d7cdb55d Iustin Pop
  This function will return a list of (node, number of votes), ordered
1115 d7cdb55d Iustin Pop
  by the number of votes. Errors will be denoted by the key 'None'.
1116 d7cdb55d Iustin Pop

1117 d7cdb55d Iustin Pop
  Note that the sum of votes is the number of nodes this machine
1118 d7cdb55d Iustin Pop
  knows, whereas the number of entries in the list could be different
1119 d7cdb55d Iustin Pop
  (if some nodes vote for another master).
1120 d7cdb55d Iustin Pop

1121 d7cdb55d Iustin Pop
  We remove ourselves from the list since we know that (bugs aside)
1122 d7cdb55d Iustin Pop
  since we use the same source for configuration information for both
1123 d7cdb55d Iustin Pop
  backend and boostrap, we'll always vote for ourselves.
1124 d7cdb55d Iustin Pop

1125 1c3231aa Thomas Thrainer
  @type node_names: list
1126 1c3231aa Thomas Thrainer
  @param node_names: the list of nodes to query for master info; the current
1127 5bbd3f7f Michael Hanselmann
      node will be removed if it is in the list
1128 d7cdb55d Iustin Pop
  @rtype: list
1129 d7cdb55d Iustin Pop
  @return: list of (node, votes)
1130 d7cdb55d Iustin Pop

1131 d7cdb55d Iustin Pop
  """
1132 b705c7a6 Manuel Franceschini
  myself = netutils.Hostname.GetSysName()
1133 d7cdb55d Iustin Pop
  try:
1134 1c3231aa Thomas Thrainer
    node_names.remove(myself)
1135 d7cdb55d Iustin Pop
  except ValueError:
1136 d7cdb55d Iustin Pop
    pass
1137 1c3231aa Thomas Thrainer
  if not node_names:
1138 d7cdb55d Iustin Pop
    # no nodes left (eventually after removing myself)
1139 d7cdb55d Iustin Pop
    return []
1140 cb8028f3 Jose A. Lopes
  results = rpc.BootstrapRunner().call_master_node_name(node_names)
1141 d7cdb55d Iustin Pop
  if not isinstance(results, dict):
1142 d7cdb55d Iustin Pop
    # this should not happen (unless internal error in rpc)
1143 d7cdb55d Iustin Pop
    logging.critical("Can't complete rpc call, aborting master startup")
1144 1c3231aa Thomas Thrainer
    return [(None, len(node_names))]
1145 d7cdb55d Iustin Pop
  votes = {}
1146 1c3231aa Thomas Thrainer
  for node_name in results:
1147 1c3231aa Thomas Thrainer
    nres = results[node_name]
1148 3cebe102 Michael Hanselmann
    msg = nres.fail_msg
1149 cb8028f3 Jose A. Lopes
1150 2a52a064 Iustin Pop
    if msg:
1151 1c3231aa Thomas Thrainer
      logging.warning("Error contacting node %s: %s", node_name, msg)
1152 cb8028f3 Jose A. Lopes
      node = None
1153 cb8028f3 Jose A. Lopes
    else:
1154 cb8028f3 Jose A. Lopes
      node = nres.payload
1155 cb8028f3 Jose A. Lopes
1156 cb8028f3 Jose A. Lopes
    if node not in votes:
1157 cb8028f3 Jose A. Lopes
      votes[node] = 1
1158 cb8028f3 Jose A. Lopes
    else:
1159 cb8028f3 Jose A. Lopes
      votes[node] += 1
1160 d7cdb55d Iustin Pop
1161 d7cdb55d Iustin Pop
  vote_list = [v for v in votes.items()]
1162 d7cdb55d Iustin Pop
  # sort first on number of votes then on name, since we want None
1163 d7cdb55d Iustin Pop
  # sorted later if we have the half of the nodes not responding, and
1164 d7cdb55d Iustin Pop
  # half voting all for the same master
1165 d7cdb55d Iustin Pop
  vote_list.sort(key=lambda x: (x[1], x[0]), reverse=True)
1166 d7cdb55d Iustin Pop
1167 d7cdb55d Iustin Pop
  return vote_list