diff --git a/NEWS b/NEWS index dc8cc90686002d809638b4d79f586172360ab3a1..768dc728758de88aa8f403bbb44ff813341c2d12 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,9 @@ +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 diff --git a/README b/README index 1d8b8833cba4827d0c66467e24e5b86cfc349fab..0b052525ddbe934a725c1ce2443442a432bdbc8e 100644 --- a/README +++ b/README @@ -1,7 +1,7 @@ -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 diff --git a/configure.ac b/configure.ac index 75e3531b4fbfa576aaf3de9f285d4537281125f6..19e0bf3ae9168c4e7caa4e27b7356690b91aff3c 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ 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, diff --git a/daemons/ganeti-watcher b/daemons/ganeti-watcher index 64eda10d9724dc2131c42d502a9f999c653fb0a8..3cf96e5be6e8a9767f4fe3848b6dc14584d4db9f 100755 --- a/daemons/ganeti-watcher +++ b/daemons/ganeti-watcher @@ -39,6 +39,7 @@ from ganeti import serializer from ganeti import errors from ganeti import opcodes from ganeti import cli +from ganeti import luxi MAXTRIES = 5 @@ -69,6 +70,16 @@ def Indent(s, prefix='| '): 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. @@ -448,6 +459,7 @@ def main(): utils.SetupLogging(constants.LOG_WATCHER, debug=options.debug, stderr_logging=options.debug) + update_file = True try: notepad = WatcherState() try: @@ -455,7 +467,17 @@ def main(): 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) @@ -465,7 +487,10 @@ def main(): 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: diff --git a/doc/rapi.rst b/doc/rapi.rst index c2ed7c459789530186f84f5286daeab18f71626f..8dc8f3b722c13cdb026f407a612a19ce13e89aed 100644 --- a/doc/rapi.rst +++ b/doc/rapi.rst @@ -49,7 +49,7 @@ Python :: import urllib2 - f = urllib2.urlopen('https://CLUSTERNAME:5080/info') + f = urllib2.urlopen('https://CLUSTERNAME:5080/2/info') print f.read() @@ -63,7 +63,7 @@ JavaScript :: - var url = 'https://CLUSTERNAME:5080/info'; + var url = 'https://CLUSTERNAME:5080/2/info'; var info; var xmlreq = new XMLHttpRequest(); xmlreq.onreadystatechange = function () { diff --git a/lib/cmdlib.py b/lib/cmdlib.py index 1a9e85f9f89a72fed66fb9a4ff120b99cff2cdbb..a71c5d7ab83643f8613ecccec3a3d8f693734fac 100644 --- a/lib/cmdlib.py +++ b/lib/cmdlib.py @@ -1417,7 +1417,7 @@ class LUSetClusterParams(LogicalUnit): _OP_REQP = [] REQ_BGL = False - def CheckParameters(self): + def CheckArguments(self): """Check parameters """ @@ -1426,7 +1426,7 @@ class LUSetClusterParams(LogicalUnit): 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: @@ -5939,7 +5939,7 @@ class LUSetInstanceParams(LogicalUnit): 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, @@ -6752,6 +6752,8 @@ class IAllocator(object): "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 diff --git a/lib/hypervisor/hv_kvm.py b/lib/hypervisor/hv_kvm.py index ee33894806fc7135863cfb5e20e48d5dff1f9a5f..3dec1788fea2313be36399de92325eb877bbd125 100644 --- a/lib/hypervisor/hv_kvm.py +++ b/lib/hypervisor/hv_kvm.py @@ -194,9 +194,9 @@ class KVMHypervisor(hv_base.BaseHypervisor): 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) diff --git a/lib/rapi/rlib2.py b/lib/rapi/rlib2.py index 9e617bf788acccb4af715c943c51b52e3ba22d50..79b95da16db810cf2c228db8d3f373e0fcdaab06 100644 --- a/lib/rapi/rlib2.py +++ b/lib/rapi/rlib2.py @@ -34,6 +34,7 @@ I_FIELDS = ["name", "admin_state", "os", "pnode", "snodes", "disk_template", "nic.ips", "nic.macs", "nic.bridges", + "network_port", "disk.sizes", "disk_usage", "beparams", "hvparams", "oper_state", "oper_ram", "status", diff --git a/man/gnt-instance.sgml b/man/gnt-instance.sgml index edf267eecac141efb276cbcf64f7983ce783218b..8ca11dec891c56945ffccadecaa2fbe18c493f3a 100644 --- a/man/gnt-instance.sgml +++ b/man/gnt-instance.sgml @@ -460,7 +460,10 @@ 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> diff --git a/qa/qa_instance.py b/qa/qa_instance.py index fe5dfb58d289ed819b18016b51a9d55bff18e480..af3afeb6af10295f027240cd7213f884008cb4d3 100644 --- a/qa/qa_instance.py +++ b/qa/qa_instance.py @@ -170,7 +170,7 @@ def TestInstanceModify(instance): ["-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 diff --git a/scripts/gnt-instance b/scripts/gnt-instance index 7b93e3bc150b53eb6663cb5e5560a05fb6055822..a54672c9003f3e59572f8d57f882f3465359f4e0 100755 --- a/scripts/gnt-instance +++ b/scripts/gnt-instance @@ -154,29 +154,6 @@ def _ConfirmOperation(inames, text): 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.