+Version 2.0 release candidate 5
+ - fix a couple of bugs (validation, argument checks)
+ - fix gnt-cluster getmaster on non-master nodes (regression)
+ - some small improvements to RAPI and IAllocator
+ - make watcher automatically start the master daemon if down
+
Version 2.0 release candidate 4
- change the OS list to not require locks; this helps with big
clusters
-Ganeti 1.2
+Ganeti 2.0
==========
-For installation instructions, read the INSTALL and the doc/install.pdf
+For installation instructions, read the INSTALL and the doc/install.html
files.
For a brief introduction, read the ganeti(7) manpage and the other pages
m4_define([gnt_version_major], [2])
m4_define([gnt_version_minor], [0])
m4_define([gnt_version_revision], [0])
-m4_define([gnt_version_suffix], [~rc4])
+m4_define([gnt_version_suffix], [~rc5])
m4_define([gnt_version_full],
m4_format([%d.%d.%d%s],
gnt_version_major, gnt_version_minor,
from ganeti import errors
from ganeti import opcodes
from ganeti import cli
+from ganeti import luxi
MAXTRIES = 5
return "%s%s\n" % (prefix, ('\n' + prefix).join(s.splitlines()))
+def StartMaster():
+ """Try to start the master daemon.
+
+ """
+ result = utils.RunCmd(['ganeti-masterd'])
+ if result.failed:
+ logging.error("Can't start the master daemon: output '%s'", result.output)
+ return not result.failed
+
+
class WatcherState(object):
"""Interface to a state file recording restart attempts.
utils.SetupLogging(constants.LOG_WATCHER, debug=options.debug,
stderr_logging=options.debug)
+ update_file = True
try:
notepad = WatcherState()
try:
client = cli.GetClient()
except errors.OpPrereqError:
# this is, from cli.GetClient, a not-master case
+ logging.debug("Not on master, exiting")
sys.exit(constants.EXIT_SUCCESS)
+ except luxi.NoMasterError, err:
+ logging.warning("Master seems to be down (%s), trying to restart",
+ str(err))
+ if not StartMaster():
+ logging.critical("Can't start the master, exiting")
+ update_file = False
+ sys.exit(constants.EXIT_FAILURE)
+ # else retry the connection
+ client = cli.GetClient()
try:
watcher = Watcher(options, notepad)
watcher.Run()
finally:
- notepad.Save()
+ if update_file:
+ notepad.Save()
+ else:
+ logging.debug("Not updating status file due to failure")
except SystemExit:
raise
except NotMasterError:
::
import urllib2
- f = urllib2.urlopen('https://CLUSTERNAME:5080/info')
+ f = urllib2.urlopen('https://CLUSTERNAME:5080/2/info')
print f.read()
::
- var url = 'https://CLUSTERNAME:5080/info';
+ var url = 'https://CLUSTERNAME:5080/2/info';
var info;
var xmlreq = new XMLHttpRequest();
xmlreq.onreadystatechange = function () {
_OP_REQP = []
REQ_BGL = False
- def CheckParameters(self):
+ def CheckArguments(self):
"""Check parameters
"""
if self.op.candidate_pool_size is not None:
try:
self.op.candidate_pool_size = int(self.op.candidate_pool_size)
- except ValueError, err:
+ except (ValueError, TypeError), err:
raise errors.OpPrereqError("Invalid candidate_pool_size value: %s" %
str(err))
if self.op.candidate_pool_size < 1:
self.warn.append("Can't get info from primary node %s" % pnode)
else:
if not instance_info.failed and instance_info.data:
- current_mem = instance_info.data['memory']
+ current_mem = int(instance_info.data['memory'])
else:
# Assume instance not running
# (there is a slight race condition here, but it's not very probable,
"disk_template": iinfo.disk_template,
"hypervisor": iinfo.hypervisor,
}
+ pir["disk_space_total"] = _ComputeDiskSize(iinfo.disk_template,
+ pir["disks"])
instance_data[iinfo.name] = pir
data["instances"] = instance_data
while arg_list:
arg = arg_list.pop(0)
if arg == '-m':
- memory = arg_list.pop(0)
+ memory = int(arg_list.pop(0))
elif arg == '-smp':
- vcpus = arg_list.pop(0)
+ vcpus = int(arg_list.pop(0))
return (instance_name, pid, memory, vcpus, stat, times)
"pnode", "snodes",
"disk_template",
"nic.ips", "nic.macs", "nic.bridges",
+ "network_port",
"disk.sizes", "disk_usage",
"beparams", "hvparams",
"oper_state", "oper_ram", "status",
initrd to boot the instance with. Xen PVM instances
can use this always, while for KVM if this option is
only used if the <option>kernel_path</option> option
- is also specified.
+ is also specified. You can pass here either an
+ absolute filename (the path to the initrd) if you
+ want to use an initrd, or use the format
+ <userinput>no_initrd_path</userinput> for no initrd.
</para>
</listitem>
</varlistentry>
["-H", "%s=%s" % (constants.HV_KERNEL_PATH, test_kernel)],
["-H", "%s=%s" % (constants.HV_KERNEL_PATH, constants.VALUE_DEFAULT)],
["-H", "%s=%s" % (constants.HV_INITRD_PATH, test_initrd)],
- ["-H", "%s=%s" % (constants.HV_INITRD_PATH, constants.VALUE_NONE)],
+ ["-H", "no_%s" % (constants.HV_INITRD_PATH, )],
["-H", "%s=%s" % (constants.HV_INITRD_PATH, constants.VALUE_DEFAULT)],
# TODO: bridge tests
return choice
-def _TransformPath(user_input):
- """Transform a user path into a canonical value.
-
- This function transforms the a path passed as textual information
- into the constants that the LU code expects.
-
- """
- if user_input:
- if user_input.lower() == "default":
- result_path = constants.VALUE_DEFAULT
- elif user_input.lower() == "none":
- result_path = constants.VALUE_NONE
- else:
- if not os.path.isabs(user_input):
- raise errors.OpPrereqError("Path '%s' is not an absolute filename" %
- user_input)
- result_path = user_input
- else:
- result_path = constants.VALUE_DEFAULT
-
- return result_path
-
-
def _EnsureInstancesExist(client, names):
"""Check for and ensure the given instance names exist.