File pacemaker_starter.py of Package pacemaker-pygui
#!/usr/bin/python
import sys, os
try:
import pygtk
pygtk.require("2.0")
except:
pass
try:
import gtk
import gtk.glade
except:
print "Failed to import gtk.glade"
sys.exit(1)
top_window = None
totem_option_table = {
"version":{"doc":"The only valid version is 2",
"type":"int",
"default_value":2,
"suggested_value":2},
"nodeid":{"doc":"The fixed 32 bit value to indentify node to cluster membership. Optional for IPv4, and required for IPv6. 0 is reserved for other usage",
"type":"int",
"default_value":70912},
"clear_node_high_bit":{"doc":"To make sure the auto-generated nodeid is positive",
"default_value":"yes"},
"secauth":{"doc":"HMAC/SHA1 should be used to authenticate all message",
"default_value":"off"},
"rrp_mode":{"doc":"The mode for redundant ring. None is used when only 1 interface specified, otherwise, only active or passive may be choosen",
"type":"select[none,active,passive]", "default_value":"none"},
"netmtu":{"doc":"Size of MTU", "type":"int", "default_value":1500},
"threads":{"doc":"How many threads should be used to encypt and sending message. Only have meanings when secauth is turned on",
"type":"int", "default_value":0},
"vsftype":{"doc":"The virtual synchrony filter type used to indentify a primary component. Change with care.",
"default_value":"ykd",
"suggested_value":"none"},
"token":{"doc":"Timeout for a token lost. in ms",
"type":"int", "default_value":1000,
"suggested_value":10000},
"token_retransmit":{"doc":"How long before receving a token then token is retransmitted. Don't change this value.",
"type":"int", "default_value":238},
"hold":{"doc":"How long the token should be held by representative when protocol is under low utilization. Don't change this value.",
"type":"int", "default_value":180},
"token_retransmits_before_loss_const":{"doc":"How many token retransmits should be attempted before forming a new configuration.",
"type":"int", "default_value":4,
"suggested_value":20},
"join":{"doc":"How long to wait for join messages in membership protocol. in ms",
"type":"int", "default_value":50,
"suggested_value":60},
"send_join":{"doc":"This timeout specifies in milliseconds an upper range between 0 and send_join to wait before sending a join message.",
"type":"int", "default_value":0},
"consensus":{"doc":"How long to wait for consensus to be achieved before starting a new round of membership configuration.",
"type":"int", "default_value":800,
"suggested_value":4800},
"merge":{"doc":"How long to wait before checking for a partition when no multicast traffic is being sent.",
"type":"int", "default_value":200},
"downcheck":{"doc":"How long to wait before checking that a network interface is back up after it has been downed.",
"type":"int", "default_value":1000},
"fail_to_recv_const":{"doc":"How many rotations of the token without receiving any of the messages when messages should be received may occur before a new configuration is formed",
"type":"int", "default_value":50},
"seqno_unchanged_const":{"doc":"How many rotations of the token without any multicast traffic should occur before the merge detection timeout is started.",
"type":"int", "default_value":30},
"heartbeat_failure_allowed":{"doc":"Configures the optional HeartBeating mechanism for faster failure detection. 0 for disable.", "type":"int", "default_value":0},
"max_network_delay":{"doc":"The approximate delay that your network takes to transport one packet from one machine to another.",
"type":"int", "default_value":50},
"window_size":{"doc":"The maximum number of messages that may be sent on one token rotation.",
"type":"int", "default_value":50},
"max_messages":{"doc":"The maximum number of messages that may be sent by one processor on receipt of the token.",
"type":"int", "default_value":17,
"suggested_value":20},
"rrp_problem_count_timeout":{"doc":"The time in milliseconds to wait before decrementing the problem count by 1 for a particular ring to ensure a link is not marked faulty for transient network failures.",
"type":"int", "default_value":2000},
"rrp_problem_count_threshhold":{"doc":"The number of times a problem is detected with a link before setting the link faulty.",
"type":"int", "default_value":10},
"rrp_token_expired_timeout":{"doc":"This specifies the time in milliseconds to increment the problem counter for the redundant ring protocol after not having received a token from all rings for a particular processor.", "type":"int", "default_value":47},
"keyfile":{"doc":"Location of key file. If not set, it defaults to the environoment OPENAIS_TOTEM_AUTHKEY_FILE, then /etc/ais/authkey", "default_value":"/etc/ais/authkey"},
"key":{"doc":"The key itself in the configuration file. Should be 128 characters. Dont use the default value", "default_value":"CatchMeeCatchMeeCatchMeeCatchMeeCatchMeeCatchMeeCatchMeeCatchMeeCatchMeeCatchMeeCatchMeeCatchMeeCatchMeeCatchMeeCatchMeeCatchMee"}
}
aisexec_option_table = {
"user":{"doc":"User to run aisexec as. Needs to be root for Pacemaker", "default_value":"root"},
"group":{"doc":"Group to run aisexec as. Needs to be root for Pacemaker", "default_value":"root"}}
service_option_table = {
"name":{"doc":"The name of the service", "default_value":"pacemaker"},
"ver":{"doc":"Version", "default_value":"0"},
"use_mgmtd":{"doc":"Default to start mgmtd with pacemaker", "default_value":"yes"},
"expected_nodes":{"doc":"Nodes we expected to see in the cluster", "default_value":2},
"expected_votes":{"doc":"Votes we expected to see in the cluster", "default_value":2},
"quorum_votes":{"doc":"Votes needed to have the quorum", "default_value":1},
"use_logd":{"doc":"Use logd for pacemaker", "default_value":"no"},
}
interface_option_table = {
"ringnumber":{"doc":"The ringnumber assigned to this interface setting", "default_value":0, "type":"int"},
"bindnetaddr":{"doc":"Network Address to be bind for this interface setting", "default_value":0},
"mcastaddr":{"doc":"The multicast address to be used", "default_value":0},
"mcastport":{"doc":"The multicast port to be used", "default_value":0, "type":"int"},
}
event_option_table = {
"delivery_queue_size":{"doc":"The full size of the outgoing delivery queue to the application", "default_value":1000},
"delivery_queue_resume":{"doc":"When new events can be accepted by the event service when the delivery queue count of pending messages has reached this value",
"default_value":500},
}
amf_option_table = {
"mode":{"doc":"Enable or disable AMF ", "default_value":"disable", "suggested_value":"disable"},
}
logging_option_table = {
"debug":{"doc":"Whether or not turning on the debug information in the log", "default_value":"off",
"suggested_value":"off"},
"fileline":{"doc":"Logging file line in the source code as well", "default_value":"off",
"suggested_value":"off"},
"to_syslog":{"doc":"Log to syslog", "default_value":"yes",
"suggested_value":"yes"},
"to_stderr":{"doc":"Log to the standard error output", "default_value":"yes", "suggested_value":"yes"},
"to_file":{"doc":"Log to a specified file", "default_value":"no", "suggested_value":"no"},
"logfile":{"doc":"Log to be saved in this specified file", "default_value":"/tmp/saved_pacemaker_log"},
"syslog_facility":{"doc":"Facility in syslog", "default_value":"daemon", "suggested_value":"daemon"},
"timestamp":{"doc":"Log timestamp as well", "default_value":"on", "suggested_value":"on"},
}
logger_option_table = {
"ident":{"doc":"Ident for the logger, i.e. AMF", "default_value":"AMF"},
"debug":{"doc":"Enable debug for this logger.", "default_value":"on"},
"tags":{"doc":"Tags used for this logger.", "default_value":"enter|leave|trace1"},
}
totem_options = {"interface":[]}
ais_options = {}
pacemaker_service_options = {}
service_options = {}
logging_options = {"logger":[]}
amf_options = {}
event_options = {}
def strip_comments_and_pending_space(line):
return line.split('#')[0].rstrip()
def get_next_line(ff):
l = ff.next()
return strip_comments_and_pending_space(l)
def is_ais_true(s):
return (s == "true" or s == "on" or s == "yes" or s == "y" or s == "1")
def generate_default_ais_options():
ais_options["user"] = "root"
ais_options["group"] = "root"
def fulfill_default_amf_options():
if amf_options.get("mode", None) == None:
amf_options["mode"] = "disable"
def fulfill_default_pacemaker_options ():
pacemaker_service_options["name"] = "pacemaker"
pacemaker_service_options["ver"] = "0"
def fulfill_default_logging_options ():
for opt in logging_option_table.keys():
if opt == "logger": continue
sv = logging_option_table[opt].get("suggested_value", None)
v = logging_options.get(opt, None)
if v == None and sv != None:
logging_options[opt] = sv
def fulfill_suggested_totem_options():
totem_options["version"] = 2
for opt in totem_option_table.keys():
if opt == "interface": continue
sv = totem_option_table[opt].get("suggested_value", None)
v = totem_options.get(opt, None)
if v == None and sv != None:
totem_options[opt] = sv
def print_ais_options(f):
f.write("aisexec {\n")
for key in ais_options.keys():
f.write("\t#%s\n\n" % (aisexec_option_table[key]["doc"]))
f.write("\t%s:\t%s\n\n" % (key, ais_options[key]))
f.write("}\n")
def print_amf_options(f):
f.write("amf {\n")
for key in amf_options.keys ():
f.write("\t#%s\n\n" % (amf_option_table[key]["doc"]))
f.write("\t%s:\t%s\n\n" % (key, amf_options[key]))
f.write("}\n")
def print_event_options(f):
if event_options == {}: return
f.write("event {\n")
for key in event_options.keys ():
f.write("\t#%s\n\n" % (event_option_table[key]["doc"]))
f.write("\t%s:\t%s\n\n" % (key, event_options[key]))
f.write("}\n")
def print_service_options(f):
for key in service_options.keys():
f.write("service {\n")
for k1 in service_options[key].keys():
f.write("\t%s:\t%s\n\n" % (k1, service_options[key][k1]))
f.write("}\n")
def print_pacemaker_service_options(f):
f.write("service {\n")
for key in pacemaker_service_options.keys():
if service_option_table.get(key, None) != None:
f.write("\t#%s\n\n" % (service_option_table[key]["doc"]))
f.write("\t%s:\t%s\n\n" % (key, pacemaker_service_options[key]))
f.write("}\n")
def print_logging_options(f):
f.write("logging {\n")
for key in logging_options.keys():
if key == "logger":
for log in logging_options["logger"]:
f.write("\tlogger {\n")
for l in log.keys():
f.write("\t\t#%s\n\n" % (logger_option_table[l]["doc"]))
f.write("\t\t%s:\t%s\n\n" % (l, log[l]))
f.write("\t}\n")
continue
f.write("\t#%s\n\n" % (logging_option_table[key]["doc"]))
f.write("\t%s:\t%s\n\n" % (key, logging_options[key]))
f.write("}\n")
def print_totem_options(f):
f.write("totem {\n")
for key in totem_options.keys():
if key == "interface":
for inf in totem_options["interface"]:
f.write("\tinterface {\n")
for k in inf.keys():
f.write("\t\t#%s\n\n" % (interface_option_table[k]["doc"]))
f.write("\t\t%s:\t%s\n\n" % (k, inf[k]))
f.write("\t}\n")
continue
f.write("\t#%s\n\n" % (totem_option_table[key]["doc"]))
f.write("\t%s:\t%s\n\n" % (key, totem_options[key]))
# We print out all possible configurations as well
for opt in totem_option_table.keys():
v = totem_options.get(opt, None)
if v == None:
f.write("\t#%s\n\n" % (totem_option_table[opt]["doc"]))
f.write("\t#%s:\t%s\n\n" % (opt, totem_option_table[opt]["default_value"]))
f.write("}\n")
def file_parser(file):
global ais_options
global totem_options
global pacemaker_service_options
global service_options
global logging_options
global amf_options
global event_options
for l in file:
i = strip_comments_and_pending_space(l)
if i == "":
continue
if i[-1] == "{":
i = i.lstrip().split(" ")[0]
if i == "aisexec":
ais_options = opt_parser(file, aisexec_option_table)
elif i == "service":
o = opt_parser(file, service_option_table)
if o.get("name", "") == "pacemaker":
pacemaker_service_options = o
elif o.get("name", "") != "":
service_options[o["name"]] = o
else:
pass
elif i == "totem":
totem_options = opt_parser(file, totem_option_table)
elif i == "logging":
logging_options = opt_parser(file, logging_option_table)
elif i == "amf":
amf_options = opt_parser(file, amf_option_table)
elif i == "event":
event_options = opt_parser(file, event_option_table)
else:
pass
def opt_parser(file, options):
result = {}
i = ""
while (i == ""):
i = get_next_line(file)
while (i[-1] != "}"):
if (i[-1] == "{"):
if i.lstrip().split(" ")[0] == "interface":
infs = result.get("interface", [])
infs.append(opt_parser(file, interface_option_table))
result["interface"] = infs
elif i.lstrip().split(" ")[0] == "logger":
logs = result.get("logger", [])
logs.append(opt_parser(file, logger_option_table))
result["logger"] = logs
else:
msgbox("Unknown sub-directive %s found. Ignore it" % (i.lstrip().split(" ")[0]))
while (i[-1] != "}"):
i = get_next_line(file)
i = get_next_line(file)
while ( i == ""):
i = get_next_line(file)
continue
opt = i.split(":")
try:
doc = options[opt[0].strip()]["doc"]
except KeyError:
print "Unknown options", opt[0].strip()
if options == service_option_table:
result[opt[0].strip()] = opt[1].strip()
else:
msgbox("Unknown options %s found, ignore it" % (opt[0].strip()))
else:
if options[opt[0].strip()].get("type", "string") == "int":
try:
result[opt[0].strip()] = int(opt[1].strip())
except ValueError:
msgbox("Invalid option %s found, default to %s" % (opt[0].strip(), options[opt[0].strip()]["default_value"]))
result[opt[0].strip()] = options[opt[0].strip()]["default_value"]
else:
result[opt[0].strip()] = opt[1].strip()
i = ""
while (i == ""):
i = get_next_line(file)
return result.copy()
def validate_conf():
if totem_options.get("version", 0) != 2:
return 1, "Version has to be set to 2"
inf1 = get_interface0()
inf2 = get_interface1()
if inf1 == None and inf2 != None:
return 1, "Ringnumber 1 is specified while ringnumber 0 is not"
if len(totem_options.get("interface", [])) == 0:
return 1, "No interface specified"
if len(totem_options.get("interface", []))>2:
return 1, "More then 2 interfaces specified"
for inf in totem_options["interface"]:
if inf.get("mcastaddr", "") == "":
return 1, "No multicast address specified"
if inf.get("mcastport", 0) == 0:
return 1, "No multicast port specified"
if inf.get("ringnumber", -1) != 0 and inf.get("ringnumber", -1) != 1:
return 1, "Ring Number must be 0 or 1, but got %d" %(inf.get("ringnumber", -1))
try:
inf.get("mcastaddr", "").index(':')
if totem_options.get("nodeid", 0) == 0:
return 1, "Node ID must be specified for IPv6"
except ValueError:
pass
return 0, "OK"
def get_interface0():
for inf in totem_options.get("interface", []):
if inf["ringnumber"] == 0:
return inf
else:
return None
def get_interface1():
for inf in totem_options.get("interface", []):
if inf["ringnumber"] == 1:
return inf
else:
return None
def init_options():
generate_default_ais_options()
fulfill_default_amf_options()
fulfill_default_pacemaker_options()
fulfill_default_logging_options()
fulfill_suggested_totem_options()
def load_ais_conf(filename):
try:
f = open(filename, "r")
file_parser(f)
f.close()
except IOError:
f = open(filename, "w")
f.write(" ")
f.close()
load_ais_conf(filename)
top_window = None
def msgbox(msg) :
global top_window
dialog = gtk.Dialog("Message", top_window, gtk.DIALOG_MODAL, (gtk.STOCK_OK, True))
dialog.set_border_width(5)
im=gtk.Image()
im.set_from_stock(gtk.STOCK_DIALOG_INFO, gtk.ICON_SIZE_DIALOG)
hb=gtk.HBox()
hb.pack_start(im)
label = gtk.Label(msg)
label.set_selectable(True)
label.set_line_wrap(True)
hb.pack_start(label)
dialog.vbox.pack_start(hb)
dialog.show_all()
save_top_window = top_window
top_window = dialog
dialog.run()
top_window = save_top_window
dialog.destroy()
class OpenAISConfDialog:
def toggle_interface2(self, interface2):
if self.wTree.get_widget("chk_interface2").get_active():
self.wTree.get_widget("text_bindnetaddr2").set_sensitive(True)
self.wTree.get_widget("text_mcastaddr2").set_sensitive(True)
self.wTree.get_widget("text_mcastport2").set_sensitive(True)
else:
self.wTree.get_widget("text_bindnetaddr2").set_sensitive(False)
self.wTree.get_widget("text_mcastaddr2").set_sensitive(False)
self.wTree.get_widget("text_mcastport2").set_sensitive(False)
def toggle_secauth(self, secauth):
if secauth.get_active():
self.wTree.get_widget("text_threads").set_sensitive(True)
else:
self.wTree.get_widget("text_threads").set_sensitive(False)
self.wTree.get_widget("text_threads").set_text(str(0))
def toggle_clearbit(self, clearbit):
if clearbit.get_active():
self.wTree.get_widget("text_nodeid").set_sensitive(False)
else:
self.wTree.get_widget("text_nodeid").set_sensitive(True)
def quit(self, menu):
self.window.destroy()
def __init__(self):
self.gladefile="/usr/share/heartbeat-gui/pacemaker-starter.glade"
self.wTree = gtk.glade.XML(self.gladefile)
self.window = self.wTree.get_widget("top_window")
if (self.window):
self.window.connect("destroy", gtk.main_quit)
self.wTree.get_widget("SaveMenu").connect("activate", self.save_configuration)
self.wTree.get_widget("QuitMenu").connect("activate", self.quit)
# Setup tooltips
self.wTree.get_widget("text_bindnetaddr").set_tooltip_text(interface_option_table["bindnetaddr"]["doc"])
self.wTree.get_widget("text_mcastaddr").set_tooltip_text(interface_option_table["mcastaddr"]["doc"])
self.wTree.get_widget("text_mcastport").set_tooltip_text(interface_option_table["mcastport"]["doc"])
self.wTree.get_widget("text_bindnetaddr2").set_tooltip_text(interface_option_table["bindnetaddr"]["doc"])
self.wTree.get_widget("text_mcastaddr2").set_tooltip_text(interface_option_table["mcastaddr"]["doc"])
self.wTree.get_widget("text_mcastport2").set_tooltip_text(interface_option_table["mcastport"]["doc"])
self.wTree.get_widget("text_nodeid").set_tooltip_text(totem_option_table["nodeid"]["doc"])
self.wTree.get_widget("text_threads").set_tooltip_text(totem_option_table["threads"]["doc"])
self.wTree.get_widget("chk_clear_high_bit").set_tooltip_text(totem_option_table["clear_node_high_bit"]["doc"])
self.wTree.get_widget("chk_secauth").set_tooltip_text(totem_option_table["secauth"]["doc"])
self.wTree.get_widget("chk_mgmtd").set_tooltip_text(service_option_table["use_mgmtd"]["doc"])
#Setup interface
# if only 1 interface specified, it must be ringnumber 0
if len(totem_options["interface"]) == 1:
totem_options["interface"][0]["ringnumber"] = 0
inf = get_interface0()
if inf != None:
self.wTree.get_widget("text_bindnetaddr").set_text(inf.get("bindnetaddr", ""))
self.wTree.get_widget("text_mcastaddr").set_text(inf.get("mcastaddr", ""))
self.wTree.get_widget("text_mcastport").set_text(str(inf.get("mcastport", "")))
inf = get_interface1()
self.wTree.get_widget("chk_interface2").connect("toggled", self.toggle_interface2)
if inf != None:
self.wTree.get_widget("text_bindnetaddr2").set_text(inf.get("bindnetaddr", ""))
self.wTree.get_widget("text_mcastaddr2").set_text(inf.get("mcastaddr", ""))
self.wTree.get_widget("text_mcastport2").set_text(str(inf.get("mcastport", "")))
self.wTree.get_widget("chk_interface2").set_active(True)
else:
self.wTree.get_widget("chk_interface2").set_active(False)
self.wTree.get_widget("chk_interface2").toggled()
#setup totem
if totem_options.get("nodeid", 0) != 0:
self.wTree.get_widget("text_nodeid").set_text(str(totem_options.get("nodeid", 0)))
else:
self.wTree.get_widget("text_nodeid").set_sensitive(False)
if self.wTree.get_widget("text_nodeid").get_text() != "":
self.wTree.get_widget("chk_clear_high_bit").set_active(False)
else:
self.wTree.get_widget("chk_clear_high_bit").set_active(True)
self.wTree.get_widget("chk_clear_high_bit").connect("toggled", self.toggle_clearbit)
self.wTree.get_widget("text_threads").set_text(str(totem_options.get("threads", 0)))
if int(self.wTree.get_widget("text_threads").get_text()) != 0:
self.wTree.get_widget("chk_secauth").set_active(True)
else:
self.wTree.get_widget("chk_secauth").set_active(False)
self.wTree.get_widget("text_threads").set_sensitive(False)
self.wTree.get_widget("chk_secauth").connect("toggled", self.toggle_secauth)
mg = pacemaker_service_options.get("use_mgmtd", "no")
if is_ais_true(mg):
self.wTree.get_widget("chk_mgmtd").set_active(True)
else:
self.wTree.get_widget("chk_mgmtd").set_active(False)
def sync_setting(self):
if get_interface0() == None:
totem_options["interface"].append({"ringnumber":0})
s = self.wTree.get_widget("text_bindnetaddr").get_text()
if s != "":
get_interface0()["bindnetaddr"] = s
else:
return 1, "Bind Network Address has to be assigned for the first interface"
s = self.wTree.get_widget("text_mcastaddr").get_text()
if s != "":
get_interface0()["mcastaddr"] = s
else:
return 1, "Multicast address has to be assigned for the first interface"
s = self.wTree.get_widget("text_mcastport").get_text()
if s == "":
return 1, "Multicast port has to be assigned for the first interface"
try:
i = int(s)
get_interface0()["mcastport"] = i
except ValueError:
return 1, "Multicast Port has to be integer, but got a %s for the first interface" % (s)
if self.wTree.get_widget("chk_interface2").get_active():
if get_interface1() == None:
# We dont have second interface yet. Create it first.
totem_options["interface"].append({"ringnumber":1})
s = self.wTree.get_widget("text_bindnetaddr2").get_text()
if s != "":
get_interface1()["bindnetaddr"] = s
else:
return 1, "Bind Network Address has to be assigned for the second interface"
s = self.wTree.get_widget("text_mcastaddr2").get_text()
if s != "":
get_interface1()["mcastaddr"] = s
else:
return 1, "Multicast address has to be assigned for the second interface"
s = self.wTree.get_widget("text_mcastport2").get_text()
if s == "":
return 1, "Multicast port has to be assigned for the second interface"
try:
i = int(s)
get_interface1()["mcastport"] = i
except ValueError:
return 1, "Multicast Port has to be integer, but got a %s for the second interface" % (s)
else:
# Dont use the redudent interface anymore, delete it
for i in range(len(totem_options["interface"])):
if totem_options["interface"][i]["ringnumber"] == 1:
del totem_options["interface"][i]
break
if len(totem_options["interface"]) == 1:
totem_options["rrp_mode"] = "none"
elif len(totem_options["interface"]) == 2:
rr = totem_options.get("rrp_mode", None)
if rr == "active" or rr == "passive":
pass
else:
totem_options["rrp_mode"] = "passive"
else:
if totem_options.get("rrp_mode", None) != None:
del totem_options["rrp_mode"]
if self.wTree.get_widget("chk_clear_high_bit").get_active():
totem_options["clear_node_high_bit"] = "yes"
try:
del totem_options["nodeid"]
except KeyError:
pass
else:
s = self.wTree.get_widget("text_nodeid").get_text()
try:
i = int(s)
totem_options["nodeid"] = i
except ValueError:
return 1, "Node ID must be assigned as a integer"
try:
del totem_options["clear_node_high_bit"]
except KeyError:
pass
if not self.wTree.get_widget("chk_secauth").get_active():
totem_options["secauth"] = "off"
try:
del totem_options["threads"]
except KeyError:
pass
else:
s = self.wTree.get_widget("text_threads").get_text()
try:
i = int(s)
if i == 0:
return 1, "Number of threads must bigger than 0"
totem_options["threads"] = i
totem_options["secauth"] = "on"
except ValueError:
return 1, "Number of threads must be integer"
if totem_options.get("keyfile", None) == None:
totem_options["keyfile"] = totem_option_table["keyfile"]["default_value"]
if self.wTree.get_widget("chk_mgmtd").get_active():
pacemaker_service_options["use_mgmtd"] = "yes"
else:
pacemaker_service_options["use_mgmtd"] = "no"
return 0, "Everything's OK"
def save_configuration(self, menu):
generate_default_ais_options()
fulfill_default_amf_options()
fulfill_default_pacemaker_options()
fulfill_default_logging_options()
fulfill_suggested_totem_options()
r, reason = self.sync_setting()
if r == 1:
msgbox(reason)
return 1
r, reason = validate_conf()
if r == 1:
msgbox(reason)
return 1
f = open("/etc/ais/openais.conf.tmp", "w")
print_ais_options(f)
print_pacemaker_service_options(f)
print_service_options(f)
print_totem_options(f)
print_logging_options(f)
print_amf_options(f)
print_event_options(f)
f.close()
if totem_options.get("secauth", "off") == "on":
msgbox("Security Authrization is turned on.\nKeyfile is /etc/ais/authkey, with 128-bytes random characters.\nYou can either create it manually or copy over from other nodes in the cluster.")
try:
os.rename("/etc/ais/openais.conf", "/etc/ais/openais.conf.bak")
os.rename("/etc/ais/openais.conf.tmp", "/etc/ais/openais.conf")
except OSError:
pass
else:
msgbox("New configuration saved")
if __name__ == "__main__":
if os.getuid() != 0:
msgbox("You must be ROOT to use this tool")
sys.exit(1)
load_ais_conf("/etc/ais/openais.conf")
r, reason = validate_conf()
if r == 1:
msgbox(reason)
hwg = OpenAISConfDialog()
gtk.main()