Statistics
| Branch: | Tag: | Revision:

root / lib / bootstrap.py @ e69d05fd

History | View | Annotate | Download (12.2 kB)

1 a0c9f010 Michael Hanselmann
#
2 a0c9f010 Michael Hanselmann
#
3 a0c9f010 Michael Hanselmann
4 a0c9f010 Michael Hanselmann
# Copyright (C) 2006, 2007, 2008 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 sha
29 a0c9f010 Michael Hanselmann
import re
30 b1b6ea87 Iustin Pop
import logging
31 a0c9f010 Michael Hanselmann
32 a0c9f010 Michael Hanselmann
from ganeti import rpc
33 a0c9f010 Michael Hanselmann
from ganeti import ssh
34 a0c9f010 Michael Hanselmann
from ganeti import utils
35 a0c9f010 Michael Hanselmann
from ganeti import errors
36 a0c9f010 Michael Hanselmann
from ganeti import config
37 a0c9f010 Michael Hanselmann
from ganeti import constants
38 b9eeeb02 Michael Hanselmann
from ganeti import objects
39 a0c9f010 Michael Hanselmann
from ganeti import ssconf
40 a0c9f010 Michael Hanselmann
41 a0c9f010 Michael Hanselmann
42 a0c9f010 Michael Hanselmann
def _InitSSHSetup(node):
43 a0c9f010 Michael Hanselmann
  """Setup the SSH configuration for the cluster.
44 a0c9f010 Michael Hanselmann

45 a0c9f010 Michael Hanselmann

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

49 a0c9f010 Michael Hanselmann
  Args:
50 a0c9f010 Michael Hanselmann
    node: the name of this host as a fqdn
51 a0c9f010 Michael Hanselmann

52 a0c9f010 Michael Hanselmann
  """
53 a0c9f010 Michael Hanselmann
  priv_key, pub_key, auth_keys = ssh.GetUserFiles(constants.GANETI_RUNAS)
54 a0c9f010 Michael Hanselmann
55 a0c9f010 Michael Hanselmann
  for name in priv_key, pub_key:
56 a0c9f010 Michael Hanselmann
    if os.path.exists(name):
57 a0c9f010 Michael Hanselmann
      utils.CreateBackup(name)
58 a0c9f010 Michael Hanselmann
    utils.RemoveFile(name)
59 a0c9f010 Michael Hanselmann
60 a0c9f010 Michael Hanselmann
  result = utils.RunCmd(["ssh-keygen", "-t", "dsa",
61 a0c9f010 Michael Hanselmann
                         "-f", priv_key,
62 a0c9f010 Michael Hanselmann
                         "-q", "-N", ""])
63 a0c9f010 Michael Hanselmann
  if result.failed:
64 a0c9f010 Michael Hanselmann
    raise errors.OpExecError("Could not generate ssh keypair, error %s" %
65 a0c9f010 Michael Hanselmann
                             result.output)
66 a0c9f010 Michael Hanselmann
67 a0c9f010 Michael Hanselmann
  f = open(pub_key, 'r')
68 a0c9f010 Michael Hanselmann
  try:
69 a0c9f010 Michael Hanselmann
    utils.AddAuthorizedKey(auth_keys, f.read(8192))
70 a0c9f010 Michael Hanselmann
  finally:
71 a0c9f010 Michael Hanselmann
    f.close()
72 a0c9f010 Michael Hanselmann
73 a0c9f010 Michael Hanselmann
74 d23ef431 Michael Hanselmann
def _InitGanetiServerSetup():
75 a0c9f010 Michael Hanselmann
  """Setup the necessary configuration for the initial node daemon.
76 a0c9f010 Michael Hanselmann

77 a0c9f010 Michael Hanselmann
  This creates the nodepass file containing the shared password for
78 a0c9f010 Michael Hanselmann
  the cluster and also generates the SSL certificate.
79 a0c9f010 Michael Hanselmann

80 a0c9f010 Michael Hanselmann
  """
81 a0c9f010 Michael Hanselmann
  # Create pseudo random password
82 33081d90 Iustin Pop
  randpass = utils.GenerateSecret()
83 d23ef431 Michael Hanselmann
84 d23ef431 Michael Hanselmann
  # and write it into the config file
85 d23ef431 Michael Hanselmann
  utils.WriteFile(constants.CLUSTER_PASSWORD_FILE,
86 d23ef431 Michael Hanselmann
                  data="%s\n" % randpass, mode=0400)
87 a0c9f010 Michael Hanselmann
88 a0c9f010 Michael Hanselmann
  result = utils.RunCmd(["openssl", "req", "-new", "-newkey", "rsa:1024",
89 a0c9f010 Michael Hanselmann
                         "-days", str(365*5), "-nodes", "-x509",
90 a0c9f010 Michael Hanselmann
                         "-keyout", constants.SSL_CERT_FILE,
91 a0c9f010 Michael Hanselmann
                         "-out", constants.SSL_CERT_FILE, "-batch"])
92 a0c9f010 Michael Hanselmann
  if result.failed:
93 a0c9f010 Michael Hanselmann
    raise errors.OpExecError("could not generate server ssl cert, command"
94 a0c9f010 Michael Hanselmann
                             " %s had exitcode %s and error message %s" %
95 a0c9f010 Michael Hanselmann
                             (result.cmd, result.exit_code, result.output))
96 a0c9f010 Michael Hanselmann
97 a0c9f010 Michael Hanselmann
  os.chmod(constants.SSL_CERT_FILE, 0400)
98 a0c9f010 Michael Hanselmann
99 a0c9f010 Michael Hanselmann
  result = utils.RunCmd([constants.NODE_INITD_SCRIPT, "restart"])
100 a0c9f010 Michael Hanselmann
101 a0c9f010 Michael Hanselmann
  if result.failed:
102 a0c9f010 Michael Hanselmann
    raise errors.OpExecError("Could not start the node daemon, command %s"
103 a0c9f010 Michael Hanselmann
                             " had exitcode %s and error %s" %
104 a0c9f010 Michael Hanselmann
                             (result.cmd, result.exit_code, result.output))
105 a0c9f010 Michael Hanselmann
106 a0c9f010 Michael Hanselmann
107 a0c9f010 Michael Hanselmann
def InitCluster(cluster_name, hypervisor_type, mac_prefix, def_bridge,
108 a0c9f010 Michael Hanselmann
                master_netdev, file_storage_dir,
109 a0c9f010 Michael Hanselmann
                secondary_ip=None,
110 a0c9f010 Michael Hanselmann
                vg_name=None):
111 a0c9f010 Michael Hanselmann
  """Initialise the cluster.
112 a0c9f010 Michael Hanselmann

113 a0c9f010 Michael Hanselmann
  """
114 a0c9f010 Michael Hanselmann
  if config.ConfigWriter.IsCluster():
115 a0c9f010 Michael Hanselmann
    raise errors.OpPrereqError("Cluster is already initialised")
116 a0c9f010 Michael Hanselmann
117 a0c9f010 Michael Hanselmann
  if hypervisor_type == constants.HT_XEN_HVM31:
118 a0c9f010 Michael Hanselmann
    if not os.path.exists(constants.VNC_PASSWORD_FILE):
119 a0c9f010 Michael Hanselmann
      raise errors.OpPrereqError("Please prepare the cluster VNC"
120 a0c9f010 Michael Hanselmann
                                 "password file %s" %
121 a0c9f010 Michael Hanselmann
                                 constants.VNC_PASSWORD_FILE)
122 a0c9f010 Michael Hanselmann
123 a0c9f010 Michael Hanselmann
  hostname = utils.HostInfo()
124 a0c9f010 Michael Hanselmann
125 a0c9f010 Michael Hanselmann
  if hostname.ip.startswith("127."):
126 a0c9f010 Michael Hanselmann
    raise errors.OpPrereqError("This host's IP resolves to the private"
127 a0c9f010 Michael Hanselmann
                               " range (%s). Please fix DNS or %s." %
128 a0c9f010 Michael Hanselmann
                               (hostname.ip, constants.ETC_HOSTS))
129 a0c9f010 Michael Hanselmann
130 a0c9f010 Michael Hanselmann
  if not utils.TcpPing(hostname.ip, constants.DEFAULT_NODED_PORT,
131 a0c9f010 Michael Hanselmann
                       source=constants.LOCALHOST_IP_ADDRESS):
132 a0c9f010 Michael Hanselmann
    raise errors.OpPrereqError("Inconsistency: this host's name resolves"
133 a0c9f010 Michael Hanselmann
                               " to %s,\nbut this ip address does not"
134 a0c9f010 Michael Hanselmann
                               " belong to this host."
135 a0c9f010 Michael Hanselmann
                               " Aborting." % hostname.ip)
136 a0c9f010 Michael Hanselmann
137 a0c9f010 Michael Hanselmann
  clustername = utils.HostInfo(cluster_name)
138 a0c9f010 Michael Hanselmann
139 a0c9f010 Michael Hanselmann
  if utils.TcpPing(clustername.ip, constants.DEFAULT_NODED_PORT,
140 a0c9f010 Michael Hanselmann
                   timeout=5):
141 a0c9f010 Michael Hanselmann
    raise errors.OpPrereqError("Cluster IP already active. Aborting.")
142 a0c9f010 Michael Hanselmann
143 a0c9f010 Michael Hanselmann
  if secondary_ip:
144 a0c9f010 Michael Hanselmann
    if not utils.IsValidIP(secondary_ip):
145 a0c9f010 Michael Hanselmann
      raise errors.OpPrereqError("Invalid secondary ip given")
146 a0c9f010 Michael Hanselmann
    if (secondary_ip != hostname.ip and
147 a0c9f010 Michael Hanselmann
        (not utils.TcpPing(secondary_ip, constants.DEFAULT_NODED_PORT,
148 a0c9f010 Michael Hanselmann
                           source=constants.LOCALHOST_IP_ADDRESS))):
149 a0c9f010 Michael Hanselmann
      raise errors.OpPrereqError("You gave %s as secondary IP,"
150 a0c9f010 Michael Hanselmann
                                 " but it does not belong to this host." %
151 a0c9f010 Michael Hanselmann
                                 secondary_ip)
152 b9eeeb02 Michael Hanselmann
  else:
153 b9eeeb02 Michael Hanselmann
    secondary_ip = hostname.ip
154 a0c9f010 Michael Hanselmann
155 a0c9f010 Michael Hanselmann
  if vg_name is not None:
156 a0c9f010 Michael Hanselmann
    # Check if volume group is valid
157 a0c9f010 Michael Hanselmann
    vgstatus = utils.CheckVolumeGroupSize(utils.ListVolumeGroups(), vg_name,
158 a0c9f010 Michael Hanselmann
                                          constants.MIN_VG_SIZE)
159 a0c9f010 Michael Hanselmann
    if vgstatus:
160 a0c9f010 Michael Hanselmann
      raise errors.OpPrereqError("Error: %s\nspecify --no-lvm-storage if"
161 a0c9f010 Michael Hanselmann
                                 " you are not using lvm" % vgstatus)
162 a0c9f010 Michael Hanselmann
163 a0c9f010 Michael Hanselmann
  file_storage_dir = os.path.normpath(file_storage_dir)
164 a0c9f010 Michael Hanselmann
165 a0c9f010 Michael Hanselmann
  if not os.path.isabs(file_storage_dir):
166 a0c9f010 Michael Hanselmann
    raise errors.OpPrereqError("The file storage directory you passed is"
167 a0c9f010 Michael Hanselmann
                               " not an absolute path.")
168 a0c9f010 Michael Hanselmann
169 a0c9f010 Michael Hanselmann
  if not os.path.exists(file_storage_dir):
170 a0c9f010 Michael Hanselmann
    try:
171 a0c9f010 Michael Hanselmann
      os.makedirs(file_storage_dir, 0750)
172 a0c9f010 Michael Hanselmann
    except OSError, err:
173 a0c9f010 Michael Hanselmann
      raise errors.OpPrereqError("Cannot create file storage directory"
174 a0c9f010 Michael Hanselmann
                                 " '%s': %s" %
175 a0c9f010 Michael Hanselmann
                                 (file_storage_dir, err))
176 a0c9f010 Michael Hanselmann
177 a0c9f010 Michael Hanselmann
  if not os.path.isdir(file_storage_dir):
178 a0c9f010 Michael Hanselmann
    raise errors.OpPrereqError("The file storage directory '%s' is not"
179 a0c9f010 Michael Hanselmann
                               " a directory." % file_storage_dir)
180 a0c9f010 Michael Hanselmann
181 a0c9f010 Michael Hanselmann
  if not re.match("^[0-9a-z]{2}:[0-9a-z]{2}:[0-9a-z]{2}$", mac_prefix):
182 a0c9f010 Michael Hanselmann
    raise errors.OpPrereqError("Invalid mac prefix given '%s'" % mac_prefix)
183 a0c9f010 Michael Hanselmann
184 a0c9f010 Michael Hanselmann
  if hypervisor_type not in constants.HYPER_TYPES:
185 a0c9f010 Michael Hanselmann
    raise errors.OpPrereqError("Invalid hypervisor type given '%s'" %
186 a0c9f010 Michael Hanselmann
                               hypervisor_type)
187 a0c9f010 Michael Hanselmann
188 a0c9f010 Michael Hanselmann
  result = utils.RunCmd(["ip", "link", "show", "dev", master_netdev])
189 a0c9f010 Michael Hanselmann
  if result.failed:
190 a0c9f010 Michael Hanselmann
    raise errors.OpPrereqError("Invalid master netdev given (%s): '%s'" %
191 a0c9f010 Michael Hanselmann
                               (master_netdev,
192 a0c9f010 Michael Hanselmann
                                result.output.strip()))
193 a0c9f010 Michael Hanselmann
194 a0c9f010 Michael Hanselmann
  if not (os.path.isfile(constants.NODE_INITD_SCRIPT) and
195 a0c9f010 Michael Hanselmann
          os.access(constants.NODE_INITD_SCRIPT, os.X_OK)):
196 a0c9f010 Michael Hanselmann
    raise errors.OpPrereqError("Init.d script '%s' missing or not"
197 a0c9f010 Michael Hanselmann
                               " executable." % constants.NODE_INITD_SCRIPT)
198 a0c9f010 Michael Hanselmann
199 a0c9f010 Michael Hanselmann
  # set up the inter-node password and certificate
200 d23ef431 Michael Hanselmann
  _InitGanetiServerSetup()
201 a0c9f010 Michael Hanselmann
202 a0c9f010 Michael Hanselmann
  # set up ssh config and /etc/hosts
203 a0c9f010 Michael Hanselmann
  f = open(constants.SSH_HOST_RSA_PUB, 'r')
204 a0c9f010 Michael Hanselmann
  try:
205 a0c9f010 Michael Hanselmann
    sshline = f.read()
206 a0c9f010 Michael Hanselmann
  finally:
207 a0c9f010 Michael Hanselmann
    f.close()
208 a0c9f010 Michael Hanselmann
  sshkey = sshline.split(" ")[1]
209 a0c9f010 Michael Hanselmann
210 a0c9f010 Michael Hanselmann
  utils.AddHostToEtcHosts(hostname.name)
211 a0c9f010 Michael Hanselmann
  _InitSSHSetup(hostname.name)
212 a0c9f010 Michael Hanselmann
213 a0c9f010 Michael Hanselmann
  # init of cluster config file
214 b9eeeb02 Michael Hanselmann
  cluster_config = objects.Cluster(
215 b9eeeb02 Michael Hanselmann
    serial_no=1,
216 b9eeeb02 Michael Hanselmann
    rsahostkeypub=sshkey,
217 b9eeeb02 Michael Hanselmann
    highest_used_port=(constants.FIRST_DRBD_PORT - 1),
218 b9eeeb02 Michael Hanselmann
    mac_prefix=mac_prefix,
219 b9eeeb02 Michael Hanselmann
    volume_group_name=vg_name,
220 b9eeeb02 Michael Hanselmann
    default_bridge=def_bridge,
221 b9eeeb02 Michael Hanselmann
    tcpudp_port_pool=set(),
222 f6bd6e98 Michael Hanselmann
    hypervisor=hypervisor_type,
223 f6bd6e98 Michael Hanselmann
    master_node=hostname.name,
224 f6bd6e98 Michael Hanselmann
    master_ip=clustername.ip,
225 f6bd6e98 Michael Hanselmann
    master_netdev=master_netdev,
226 f6bd6e98 Michael Hanselmann
    cluster_name=clustername.name,
227 f6bd6e98 Michael Hanselmann
    file_storage_dir=file_storage_dir,
228 b9eeeb02 Michael Hanselmann
    )
229 b9eeeb02 Michael Hanselmann
  master_node_config = objects.Node(name=hostname.name,
230 b9eeeb02 Michael Hanselmann
                                    primary_ip=hostname.ip,
231 b9eeeb02 Michael Hanselmann
                                    secondary_ip=secondary_ip)
232 a0c9f010 Michael Hanselmann
  cfg = config.ConfigWriter()
233 f6bd6e98 Michael Hanselmann
  cfg.InitConfig(constants.CONFIG_VERSION, cluster_config, master_node_config)
234 a0c9f010 Michael Hanselmann
235 7688d0d3 Michael Hanselmann
  ssh.WriteKnownHostsFile(cfg, constants.SSH_KNOWN_HOSTS_FILE)
236 827f753e Guido Trotter
237 b3f1cf6f Iustin Pop
  # start the master ip
238 b3f1cf6f Iustin Pop
  # TODO: Review rpc call from bootstrap
239 b3f1cf6f Iustin Pop
  rpc.call_node_start_master(hostname.name, True)
240 b3f1cf6f Iustin Pop
241 b1b6ea87 Iustin Pop
242 140aa4a8 Iustin Pop
def FinalizeClusterDestroy(master):
243 140aa4a8 Iustin Pop
  """Execute the last steps of cluster destroy
244 140aa4a8 Iustin Pop

245 140aa4a8 Iustin Pop
  This function shuts down all the daemons, completing the destroy
246 140aa4a8 Iustin Pop
  begun in cmdlib.LUDestroyOpcode.
247 140aa4a8 Iustin Pop

248 140aa4a8 Iustin Pop
  """
249 140aa4a8 Iustin Pop
  if not rpc.call_node_stop_master(master, True):
250 140aa4a8 Iustin Pop
    logging.warning("Could not disable the master role")
251 140aa4a8 Iustin Pop
  if not rpc.call_node_leave_cluster(master):
252 140aa4a8 Iustin Pop
    logging.warning("Could not shutdown the node daemon and cleanup the node")
253 140aa4a8 Iustin Pop
254 140aa4a8 Iustin Pop
255 c4b6c29c Michael Hanselmann
def SetupNodeDaemon(node, ssh_key_check):
256 827f753e Guido Trotter
  """Add a node to the cluster.
257 827f753e Guido Trotter

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

262 827f753e Guido Trotter
  Args:
263 827f753e Guido Trotter
    node: fully qualified domain name for the new node
264 827f753e Guido Trotter

265 827f753e Guido Trotter
  """
266 7688d0d3 Michael Hanselmann
  cfg = ssconf.SimpleConfigReader()
267 6b0469d2 Iustin Pop
  sshrunner = ssh.SshRunner(cfg.GetClusterName())
268 d23ef431 Michael Hanselmann
  gntpass = utils.GetNodeDaemonPassword()
269 827f753e Guido Trotter
  if not re.match('^[a-zA-Z0-9.]{1,64}$', gntpass):
270 827f753e Guido Trotter
    raise errors.OpExecError("ganeti password corruption detected")
271 827f753e Guido Trotter
  f = open(constants.SSL_CERT_FILE)
272 827f753e Guido Trotter
  try:
273 827f753e Guido Trotter
    gntpem = f.read(8192)
274 827f753e Guido Trotter
  finally:
275 827f753e Guido Trotter
    f.close()
276 827f753e Guido Trotter
  # in the base64 pem encoding, neither '!' nor '.' are valid chars,
277 827f753e Guido Trotter
  # so we use this to detect an invalid certificate; as long as the
278 827f753e Guido Trotter
  # cert doesn't contain this, the here-document will be correctly
279 827f753e Guido Trotter
  # parsed by the shell sequence below
280 827f753e Guido Trotter
  if re.search('^!EOF\.', gntpem, re.MULTILINE):
281 827f753e Guido Trotter
    raise errors.OpExecError("invalid PEM encoding in the SSL certificate")
282 827f753e Guido Trotter
  if not gntpem.endswith("\n"):
283 827f753e Guido Trotter
    raise errors.OpExecError("PEM must end with newline")
284 827f753e Guido Trotter
285 827f753e Guido Trotter
  # set up inter-node password and certificate and restarts the node daemon
286 827f753e Guido Trotter
  # and then connect with ssh to set password and start ganeti-noded
287 827f753e Guido Trotter
  # note that all the below variables are sanitized at this point,
288 827f753e Guido Trotter
  # either by being constants or by the checks above
289 827f753e Guido Trotter
  mycommand = ("umask 077 && "
290 827f753e Guido Trotter
               "echo '%s' > '%s' && "
291 827f753e Guido Trotter
               "cat > '%s' << '!EOF.' && \n"
292 827f753e Guido Trotter
               "%s!EOF.\n%s restart" %
293 d23ef431 Michael Hanselmann
               (gntpass, constants.CLUSTER_PASSWORD_FILE,
294 827f753e Guido Trotter
                constants.SSL_CERT_FILE, gntpem,
295 827f753e Guido Trotter
                constants.NODE_INITD_SCRIPT))
296 827f753e Guido Trotter
297 c4b6c29c Michael Hanselmann
  result = sshrunner.Run(node, 'root', mycommand, batch=False,
298 c4b6c29c Michael Hanselmann
                         ask_key=ssh_key_check,
299 c4b6c29c Michael Hanselmann
                         use_cluster_key=False,
300 c4b6c29c Michael Hanselmann
                         strict_host_check=ssh_key_check)
301 827f753e Guido Trotter
  if result.failed:
302 827f753e Guido Trotter
    raise errors.OpExecError("Remote command on node %s, error: %s,"
303 827f753e Guido Trotter
                             " output: %s" %
304 827f753e Guido Trotter
                             (node, result.fail_reason, result.output))
305 827f753e Guido Trotter
306 827f753e Guido Trotter
  return 0
307 827f753e Guido Trotter
308 b1b6ea87 Iustin Pop
309 b1b6ea87 Iustin Pop
def MasterFailover():
310 b1b6ea87 Iustin Pop
  """Failover the master node.
311 b1b6ea87 Iustin Pop

312 b1b6ea87 Iustin Pop
  This checks that we are not already the master, and will cause the
313 b1b6ea87 Iustin Pop
  current master to cease being master, and the non-master to become
314 b1b6ea87 Iustin Pop
  new master.
315 b1b6ea87 Iustin Pop

316 b1b6ea87 Iustin Pop
  """
317 d23ef431 Michael Hanselmann
  cfg = ssconf.SimpleConfigWriter()
318 b1b6ea87 Iustin Pop
319 b1b6ea87 Iustin Pop
  new_master = utils.HostInfo().name
320 d23ef431 Michael Hanselmann
  old_master = cfg.GetMasterNode()
321 b1b6ea87 Iustin Pop
322 b1b6ea87 Iustin Pop
  if old_master == new_master:
323 b1b6ea87 Iustin Pop
    raise errors.OpPrereqError("This commands must be run on the node"
324 b1b6ea87 Iustin Pop
                               " where you want the new master to be."
325 b1b6ea87 Iustin Pop
                               " %s is already the master" %
326 b1b6ea87 Iustin Pop
                               old_master)
327 b1b6ea87 Iustin Pop
  # end checks
328 b1b6ea87 Iustin Pop
329 b1b6ea87 Iustin Pop
  rcode = 0
330 b1b6ea87 Iustin Pop
331 b1b6ea87 Iustin Pop
  logging.info("setting master to %s, old master: %s", new_master, old_master)
332 b1b6ea87 Iustin Pop
333 b1b6ea87 Iustin Pop
  if not rpc.call_node_stop_master(old_master, True):
334 b1b6ea87 Iustin Pop
    logging.error("could disable the master role on the old master"
335 b1b6ea87 Iustin Pop
                 " %s, please disable manually", old_master)
336 b1b6ea87 Iustin Pop
337 d23ef431 Michael Hanselmann
  cfg.SetMasterNode(new_master)
338 d23ef431 Michael Hanselmann
  cfg.Save()
339 b1b6ea87 Iustin Pop
340 d23ef431 Michael Hanselmann
  # Here we have a phase where no master should be running
341 b1b6ea87 Iustin Pop
342 b1b6ea87 Iustin Pop
  if not rpc.call_upload_file(cfg.GetNodeList(),
343 d23ef431 Michael Hanselmann
                              constants.CLUSTER_CONF_FILE):
344 3b9e6a30 Iustin Pop
    logging.error("could not distribute the new simple store master file"
345 3b9e6a30 Iustin Pop
                  " to the other nodes, please check.")
346 b1b6ea87 Iustin Pop
347 b1b6ea87 Iustin Pop
  if not rpc.call_node_start_master(new_master, True):
348 b1b6ea87 Iustin Pop
    logging.error("could not start the master role on the new master"
349 b1b6ea87 Iustin Pop
                  " %s, please check", new_master)
350 b1b6ea87 Iustin Pop
    rcode = 1
351 b1b6ea87 Iustin Pop
352 b1b6ea87 Iustin Pop
  return rcode