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 905402ecdaf2d3adcf129da54a327d7d122ea46c..03476cfa881e21e37595290bdc8054cf7f680132 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 8745f2dd7440972231adc3ba1c7b3ce799bc2cdd..42a2eaf832857cb2163a7385fb962051af540ab4 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. @@ -441,6 +452,7 @@ def main(): utils.SetupLogging(constants.LOG_WATCHER, debug=options.debug, stderr_logging=options.debug) + update_file = True try: notepad = WatcherState() try: @@ -448,7 +460,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) @@ -458,7 +480,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 91bd1f7d6df59095ea48f292fcc94280a0c96a4f..be57b0161442dda96bf7b0d50d82db23e9b91da3 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 5edc7c3a364a14a8fddb8f885e1d4b426fc626af..e2aec21b8eeb5a7998bc634b92554314d4ecab2c 100644 --- a/lib/cmdlib.py +++ b/lib/cmdlib.py @@ -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 bc7294792ca9f5c5d67c3db13e8f407a391b2428..38ed993b35dd4ab8db01056dbee375aec2d77a99 100644 --- a/lib/hypervisor/hv_kvm.py +++ b/lib/hypervisor/hv_kvm.py @@ -211,9 +211,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.