X-Git-Url: https://code.grnet.gr/git/ganeti-local/blobdiff_plain/1aa88d95b3ece453b960a92e784517bf7d773785..432e8e2f3a21139d6e1bb39b4a38448e2af0f902:/lib/server/noded.py diff --git a/lib/server/noded.py b/lib/server/noded.py index 63d5e47..ba3cb90 100644 --- a/lib/server/noded.py +++ b/lib/server/noded.py @@ -1,7 +1,7 @@ # # -# Copyright (C) 2006, 2007, 2010 Google Inc. +# Copyright (C) 2006, 2007, 2010, 2011 Google Inc. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -21,7 +21,7 @@ """Ganeti node daemon""" -# pylint: disable-msg=C0103,W0142 +# pylint: disable=C0103,W0142 # C0103: Functions in this module need to have a given name structure, # and the name of the daemon doesn't match @@ -33,6 +33,7 @@ import os import sys import logging import signal +import codecs from optparse import OptionParser @@ -48,7 +49,7 @@ from ganeti import storage from ganeti import serializer from ganeti import netutils -import ganeti.http.server # pylint: disable-msg=W0611 +import ganeti.http.server # pylint: disable=W0611 queue_lock = None @@ -60,7 +61,7 @@ def _PrepareQueueLock(): @return: None for success, otherwise an exception object """ - global queue_lock # pylint: disable-msg=W0603 + global queue_lock # pylint: disable=W0603 if queue_lock is not None: return None @@ -128,7 +129,7 @@ class NodeHttpServer(http.server.HttpServer): """ # too many public methods, and unused args - all methods get params # due to the API - # pylint: disable-msg=R0904,W0613 + # pylint: disable=R0904,W0613 def __init__(self, *args, **kwargs): http.server.HttpServer.__init__(self, *args, **kwargs) self.noded_pid = os.getpid() @@ -137,8 +138,9 @@ class NodeHttpServer(http.server.HttpServer): """Handle a request. """ - if req.request_method.upper() != http.HTTP_PUT: - raise http.HttpBadRequest() + # FIXME: Remove HTTP_PUT in Ganeti 2.7 + if req.request_method.upper() not in (http.HTTP_PUT, http.HTTP_POST): + raise http.HttpBadRequest("Only PUT and POST methods are supported") path = req.request_path if path.startswith("/"): @@ -168,7 +170,7 @@ class NodeHttpServer(http.server.HttpServer): logging.exception("Error in RPC call") result = (False, "Error while executing backend function: %s" % str(err)) - return serializer.DumpJson(result, indent=False) + return serializer.DumpJson(result) # the new block devices -------------------------- @@ -184,6 +186,15 @@ class NodeHttpServer(http.server.HttpServer): return backend.BlockdevCreate(bdev, size, owner, on_primary, info) @staticmethod + def perspective_blockdev_pause_resume_sync(params): + """Pause/resume sync of a block device. + + """ + disks_s, pause = params + disks = [objects.Disk.FromDict(bdev_s) for bdev_s in disks_s] + return backend.BlockdevPauseResumeSync(disks, pause) + + @staticmethod def perspective_blockdev_wipe(params): """Wipe a block device. @@ -206,7 +217,7 @@ class NodeHttpServer(http.server.HttpServer): """Remove a block device. """ - devlist = [(objects.Disk.FromDict(ds), uid) for ds, uid in params] + devlist = [(objects.Disk.FromDict(ds), uid) for ds, uid in params[0]] return backend.BlockdevRename(devlist) @staticmethod @@ -214,11 +225,11 @@ class NodeHttpServer(http.server.HttpServer): """Assemble a block device. """ - bdev_s, owner, on_primary = params + bdev_s, owner, on_primary, idx = params bdev = objects.Disk.FromDict(bdev_s) if bdev is None: raise ValueError("can't unserialize data!") - return backend.BlockdevAssemble(bdev, owner, on_primary) + return backend.BlockdevAssemble(bdev, owner, on_primary, idx) @staticmethod def perspective_blockdev_shutdown(params): @@ -267,7 +278,7 @@ class NodeHttpServer(http.server.HttpServer): """ disks = [objects.Disk.FromDict(dsk_s) - for dsk_s in params] + for dsk_s in params[0]] return [status.ToDict() for status in backend.BlockdevGetmirrorstatus(disks)] @@ -278,10 +289,7 @@ class NodeHttpServer(http.server.HttpServer): """ (node_disks, ) = params - node_name = netutils.Hostname.GetSysName() - - disks = [objects.Disk.FromDict(dsk_s) - for dsk_s in node_disks.get(node_name, [])] + disks = [objects.Disk.FromDict(dsk_s) for dsk_s in node_disks] result = [] @@ -327,7 +335,8 @@ class NodeHttpServer(http.server.HttpServer): """ cfbd = objects.Disk.FromDict(params[0]) amount = params[1] - return backend.BlockdevGrow(cfbd, amount) + dryrun = params[2] + return backend.BlockdevGrow(cfbd, amount, dryrun) @staticmethod def perspective_blockdev_close(params): @@ -448,6 +457,15 @@ class NodeHttpServer(http.server.HttpServer): export = params[0] return backend.RemoveExport(export) + # block device --------------------- + @staticmethod + def perspective_bdev_sizes(params): + """Query the list of block devices + + """ + devices = params[0] + return backend.GetBlockDevSizes(devices) + # volume -------------------------- @staticmethod @@ -537,8 +555,9 @@ class NodeHttpServer(http.server.HttpServer): """Start an instance. """ - instance = objects.Instance.FromDict(params[0]) - return backend.StartInstance(instance) + (instance_name, startup_paused) = params + instance = objects.Instance.FromDict(instance_name) + return backend.StartInstance(instance, startup_paused) @staticmethod def perspective_migration_info(params): @@ -558,13 +577,13 @@ class NodeHttpServer(http.server.HttpServer): return backend.AcceptInstance(instance, info, target) @staticmethod - def perspective_finalize_migration(params): - """Finalize the instance migration. + def perspective_instance_finalize_migration_dst(params): + """Finalize the instance migration on the destination node. """ instance, info, success = params instance = objects.Instance.FromDict(instance) - return backend.FinalizeMigration(instance, info, success) + return backend.FinalizeMigrationDst(instance, info, success) @staticmethod def perspective_instance_migrate(params): @@ -576,6 +595,23 @@ class NodeHttpServer(http.server.HttpServer): return backend.MigrateInstance(instance, target, live) @staticmethod + def perspective_instance_finalize_migration_src(params): + """Finalize the instance migration on the source node. + + """ + instance, success, live = params + instance = objects.Instance.FromDict(instance) + return backend.FinalizeMigrationSource(instance, success, live) + + @staticmethod + def perspective_instance_get_migration_status(params): + """Reports migration status. + + """ + instance = objects.Instance.FromDict(params[0]) + return backend.GetMigrationStatus(instance).ToDict() + + @staticmethod def perspective_instance_reboot(params): """Reboot an instance. @@ -586,6 +622,15 @@ class NodeHttpServer(http.server.HttpServer): return backend.InstanceReboot(instance, reboot_type, shutdown_timeout) @staticmethod + def perspective_instance_balloon_memory(params): + """Modify instance runtime memory. + + """ + instance_dict, memory = params + instance = objects.Instance.FromDict(instance_dict) + return backend.InstanceBalloonMemory(instance, memory) + + @staticmethod def perspective_instance_info(params): """Query instance information. @@ -617,14 +662,6 @@ class NodeHttpServer(http.server.HttpServer): # node -------------------------- @staticmethod - def perspective_node_tcp_ping(params): - """Do a TcpPing on the remote node. - - """ - return netutils.TcpPing(params[1], params[2], timeout=params[3], - live_port_needed=params[4], source=params[0]) - - @staticmethod def perspective_node_has_ip_address(params): """Checks if a node has the given ip address. @@ -636,8 +673,8 @@ class NodeHttpServer(http.server.HttpServer): """Query node information. """ - vgname, hypervisor_type = params - return backend.GetNodeInfo(vgname, hypervisor_type) + (vg_names, hv_names) = params + return backend.GetNodeInfo(vg_names, hv_names) @staticmethod def perspective_etc_hosts_modify(params): @@ -656,18 +693,42 @@ class NodeHttpServer(http.server.HttpServer): return backend.VerifyNode(params[0], params[1]) @staticmethod - def perspective_node_start_master(params): - """Promote this node to master status. + def perspective_node_start_master_daemons(params): + """Start the master daemons on this node. + + """ + return backend.StartMasterDaemons(params[0]) + + @staticmethod + def perspective_node_activate_master_ip(params): + """Activate the master IP on this node. + + """ + master_params = objects.MasterNetworkParameters.FromDict(params[0]) + return backend.ActivateMasterIp(master_params, params[1]) + + @staticmethod + def perspective_node_deactivate_master_ip(params): + """Deactivate the master IP on this node. """ - return backend.StartMaster(params[0], params[1]) + master_params = objects.MasterNetworkParameters.FromDict(params[0]) + return backend.DeactivateMasterIp(master_params, params[1]) @staticmethod def perspective_node_stop_master(params): - """Demote this node from master status. + """Stops master daemons on this node. """ - return backend.StopMaster(params[0]) + return backend.StopMasterDaemons() + + @staticmethod + def perspective_node_change_master_netmask(params): + """Change the master IP netmask. + + """ + return backend.ChangeMasterNetmask(params[0], params[1], params[2], + params[3]) @staticmethod def perspective_node_leave_cluster(params): @@ -690,7 +751,6 @@ class NodeHttpServer(http.server.HttpServer): """ return backend.DemoteFromMC() - @staticmethod def perspective_node_powercycle(params): """Tries to powercycle the nod. @@ -699,7 +759,6 @@ class NodeHttpServer(http.server.HttpServer): hypervisor_type = params[0] return backend.PowercycleNode(hypervisor_type) - # cluster -------------------------- @staticmethod @@ -717,7 +776,7 @@ class NodeHttpServer(http.server.HttpServer): files are accepted. """ - return backend.UploadFile(*params) + return backend.UploadFile(*(params[0])) @staticmethod def perspective_master_info(params): @@ -861,7 +920,7 @@ class NodeHttpServer(http.server.HttpServer): """ # TODO: What if a file fails to rename? - return [backend.JobQueueRename(old, new) for old, new in params] + return [backend.JobQueueRename(old, new) for old, new in params[0]] # hypervisor --------------- @@ -898,14 +957,14 @@ class NodeHttpServer(http.server.HttpServer): """Starts an import daemon. """ - (opts_s, instance, dest, dest_args) = params + (opts_s, instance, component, (dest, dest_args)) = params opts = objects.ImportExportOptions.FromDict(opts_s) return backend.StartImportExportDaemon(constants.IEM_IMPORT, opts, None, None, objects.Instance.FromDict(instance), - dest, + component, dest, _DecodeImportExportIO(dest, dest_args)) @@ -914,14 +973,14 @@ class NodeHttpServer(http.server.HttpServer): """Starts an export daemon. """ - (opts_s, host, port, instance, source, source_args) = params + (opts_s, host, port, instance, component, (source, source_args)) = params opts = objects.ImportExportOptions.FromDict(opts_s) return backend.StartImportExportDaemon(constants.IEM_EXPORT, opts, host, port, objects.Instance.FromDict(instance), - source, + component, source, _DecodeImportExportIO(source, source_args)) @@ -955,6 +1014,13 @@ def CheckNoded(_, args): print >> sys.stderr, ("Usage: %s [-f] [-d] [-p port] [-b ADDRESS]" % sys.argv[0]) sys.exit(constants.EXIT_FAILURE) + try: + codecs.lookup("string-escape") + except LookupError: + print >> sys.stderr, ("Can't load the string-escape code which is part" + " of the Python installation. Is your installation" + " complete/correct? Aborting.") + sys.exit(constants.EXIT_FAILURE) def PrepNoded(options, _): @@ -993,7 +1059,7 @@ def PrepNoded(options, _): return (mainloop, server) -def ExecNoded(options, args, prep_data): # pylint: disable-msg=W0613 +def ExecNoded(options, args, prep_data): # pylint: disable=W0613 """Main node daemon function, executed with the PID file held. """