+ cluster_config = objects.Cluster(
+ serial_no=1,
+ rsahostkeypub=sshkey,
+ highest_used_port=(constants.FIRST_DRBD_PORT - 1),
+ mac_prefix=mac_prefix,
+ volume_group_name=vg_name,
+ default_bridge=def_bridge,
+ tcpudp_port_pool=set(),
+ master_node=hostname.name,
+ master_ip=clustername.ip,
+ master_netdev=master_netdev,
+ cluster_name=clustername.name,
+ file_storage_dir=file_storage_dir,
+ enabled_hypervisors=enabled_hypervisors,
+ default_hypervisor=default_hypervisor,
+ beparams={constants.PP_DEFAULT: beparams},
+ hvparams=hvparams,
+ candidate_pool_size=candidate_pool_size,
+ modify_etc_hosts=modify_etc_hosts,
+ )
+ master_node_config = objects.Node(name=hostname.name,
+ primary_ip=hostname.ip,
+ secondary_ip=secondary_ip,
+ serial_no=1,
+ master_candidate=True,
+ offline=False, drained=False,
+ )
+
+ sscfg = InitConfig(constants.CONFIG_VERSION,
+ cluster_config, master_node_config)
+ ssh.WriteKnownHostsFile(sscfg, constants.SSH_KNOWN_HOSTS_FILE)
+ cfg = config.ConfigWriter()
+ cfg.Update(cfg.GetClusterInfo())
+
+ # start the master ip
+ # TODO: Review rpc call from bootstrap
+ rpc.RpcRunner.call_node_start_master(hostname.name, True)
+
+
+def InitConfig(version, cluster_config, master_node_config,
+ cfg_file=constants.CLUSTER_CONF_FILE):
+ """Create the initial cluster configuration.
+
+ It will contain the current node, which will also be the master
+ node, and no instances.
+
+ @type version: int
+ @param version: configuration version
+ @type cluster_config: L{objects.Cluster}
+ @param cluster_config: cluster configuration
+ @type master_node_config: L{objects.Node}
+ @param master_node_config: master node configuration
+ @type cfg_file: string
+ @param cfg_file: configuration file path
+
+ @rtype: L{ssconf.SimpleConfigWriter}
+ @return: initialized config instance
+
+ """
+ nodes = {
+ master_node_config.name: master_node_config,
+ }
+
+ config_data = objects.ConfigData(version=version,
+ cluster=cluster_config,
+ nodes=nodes,
+ instances={},
+ serial_no=1)
+ cfg = ssconf.SimpleConfigWriter.FromDict(config_data.ToDict(), cfg_file)
+ cfg.Save()
+
+ return cfg
+
+
+def FinalizeClusterDestroy(master):
+ """Execute the last steps of cluster destroy
+
+ This function shuts down all the daemons, completing the destroy
+ begun in cmdlib.LUDestroyOpcode.
+
+ """
+ result = rpc.RpcRunner.call_node_stop_master(master, True)
+ if result.failed or not result.data:
+ logging.warning("Could not disable the master role")
+ result = rpc.RpcRunner.call_node_leave_cluster(master)
+ if result.failed or not result.data:
+ logging.warning("Could not shutdown the node daemon and cleanup the node")
+
+
+def SetupNodeDaemon(cluster_name, node, ssh_key_check):
+ """Add a node to the cluster.
+
+ This function must be called before the actual opcode, and will ssh
+ to the remote node, copy the needed files, and start ganeti-noded,
+ allowing the master to do the rest via normal rpc calls.
+
+ @param cluster_name: the cluster name
+ @param node: the name of the new node
+ @param ssh_key_check: whether to do a strict key check
+
+ """
+ sshrunner = ssh.SshRunner(cluster_name)
+
+ noded_cert = utils.ReadFile(constants.SSL_CERT_FILE)
+ rapi_cert = utils.ReadFile(constants.RAPI_CERT_FILE)
+
+ # in the base64 pem encoding, neither '!' nor '.' are valid chars,
+ # so we use this to detect an invalid certificate; as long as the
+ # cert doesn't contain this, the here-document will be correctly
+ # parsed by the shell sequence below
+ if (re.search('^!EOF\.', noded_cert, re.MULTILINE) or
+ re.search('^!EOF\.', rapi_cert, re.MULTILINE)):
+ raise errors.OpExecError("invalid PEM encoding in the SSL certificate")
+
+ if not noded_cert.endswith("\n"):
+ noded_cert += "\n"
+ if not rapi_cert.endswith("\n"):
+ rapi_cert += "\n"
+
+ # set up inter-node password and certificate and restarts the node daemon
+ # and then connect with ssh to set password and start ganeti-noded
+ # note that all the below variables are sanitized at this point,
+ # either by being constants or by the checks above
+ mycommand = ("umask 077 && "
+ "cat > '%s' << '!EOF.' && \n"
+ "%s!EOF.\n"
+ "cat > '%s' << '!EOF.' && \n"
+ "%s!EOF.\n"
+ "chmod 0400 %s %s && "
+ "%s restart" %
+ (constants.SSL_CERT_FILE, noded_cert,
+ constants.RAPI_CERT_FILE, rapi_cert,
+ constants.SSL_CERT_FILE, constants.RAPI_CERT_FILE,
+ constants.NODE_INITD_SCRIPT))
+
+ result = sshrunner.Run(node, 'root', mycommand, batch=False,
+ ask_key=ssh_key_check,
+ use_cluster_key=False,
+ strict_host_check=ssh_key_check)
+ if result.failed:
+ raise errors.OpExecError("Remote command on node %s, error: %s,"
+ " output: %s" %
+ (node, result.fail_reason, result.output))
+
+
+def MasterFailover():
+ """Failover the master node.
+
+ This checks that we are not already the master, and will cause the
+ current master to cease being master, and the non-master to become
+ new master.
+
+ """
+ sstore = ssconf.SimpleStore()
+
+ old_master, new_master = ssconf.GetMasterAndMyself(sstore)
+ node_list = sstore.GetNodeList()
+ mc_list = sstore.GetMasterCandidates()
+
+ if old_master == new_master:
+ raise errors.OpPrereqError("This commands must be run on the node"
+ " where you want the new master to be."
+ " %s is already the master" %
+ old_master)
+
+ if new_master not in mc_list:
+ mc_no_master = [name for name in mc_list if name != old_master]
+ raise errors.OpPrereqError("This node is not among the nodes marked"
+ " as master candidates. Only these nodes"
+ " can become masters. Current list of"
+ " master candidates is:\n"
+ "%s" % ('\n'.join(mc_no_master)))
+
+ vote_list = GatherMasterVotes(node_list)
+
+ if vote_list:
+ voted_master = vote_list[0][0]
+ if voted_master is None:
+ raise errors.OpPrereqError("Cluster is inconsistent, most nodes did not"
+ " respond.")
+ elif voted_master != old_master:
+ raise errors.OpPrereqError("I have wrong configuration, I believe the"
+ " master is %s but the other nodes voted for"
+ " %s. Please resync the configuration of"
+ " this node." % (old_master, voted_master))
+ # end checks
+
+ rcode = 0
+
+ logging.info("Setting master to %s, old master: %s", new_master, old_master)
+
+ result = rpc.RpcRunner.call_node_stop_master(old_master, True)
+ if result.failed or not result.data:
+ logging.error("Could not disable the master role on the old master"
+ " %s, please disable manually", old_master)
+
+ # Here we have a phase where no master should be running
+
+ # instantiate a real config writer, as we now know we have the
+ # configuration data