X-Git-Url: https://code.grnet.gr/git/ganeti-local/blobdiff_plain/2503680f1525bc8e79f208eda005e321ad560a4f..4fe80ef2ed1cda3a6357274eccafe5c1f21a5283:/lib/backend.py diff --git a/lib/backend.py b/lib/backend.py index afb3921..44e45f6 100644 --- a/lib/backend.py +++ b/lib/backend.py @@ -19,7 +19,12 @@ # 02110-1301, USA. -"""Functions used by the node daemon""" +"""Functions used by the node daemon + +@var _ALLOWED_UPLOAD_FILES: denotes which files are accepted in + the L{UploadFile} function + +""" import os @@ -115,6 +120,23 @@ def _CleanDirectory(path, exclude=None): utils.RemoveFile(full_name) +def _BuildUploadFileList(): + """Build the list of allowed upload files. + + This is abstracted so that it's built only once at module import time. + + """ + return frozenset([ + constants.CLUSTER_CONF_FILE, + constants.ETC_HOSTS, + constants.SSH_KNOWN_HOSTS_FILE, + constants.VNC_PASSWORD_FILE, + ]) + + +_ALLOWED_UPLOAD_FILES = _BuildUploadFileList() + + def JobQueuePurge(): """Removes job queue files and archived jobs. @@ -141,7 +163,7 @@ def GetMasterInfo(): master_netdev = cfg.GetMasterNetdev() master_ip = cfg.GetMasterIP() master_node = cfg.GetMasterNode() - except errors.ConfigurationError, err: + except errors.ConfigurationError: logging.exception("Cluster configuration incomplete") return (None, None, None) return (master_netdev, master_ip, master_node) @@ -320,7 +342,7 @@ def LeaveCluster(): def GetNodeInfo(vgname, hypervisor_type): - """Gives back a hash with different informations about the node. + """Gives back a hash with different information about the node. @type vgname: C{string} @param vgname: the name of the volume group to ask for disk space information @@ -585,7 +607,7 @@ def GetInstanceList(hypervisor_list): try: names = hypervisor.GetHypervisor(hname).ListInstances() results.extend(names) - except errors.HypervisorError, err: + except errors.HypervisorError: logging.exception("Error enumerating instances for hypevisor %s", hname) raise @@ -593,7 +615,7 @@ def GetInstanceList(hypervisor_list): def GetInstanceInfo(instance, hname): - """Gives back the informations about an instance as a dictionary. + """Gives back the information about an instance as a dictionary. @type instance: string @param instance: the instance name @@ -758,7 +780,7 @@ def RunRenameInstance(instance, old_name): def _GetVGInfo(vg_name): - """Get informations about the volume group. + """Get information about the volume group. @type vg_name: str @param vg_name: the volume group which we query @@ -930,7 +952,7 @@ def InstanceShutdown(instance): # test every 10secs for 2min time.sleep(1) - for dummy in range(11): + for _ in range(11): if instance.name not in GetInstanceList([hv_name]): break time.sleep(10) @@ -1044,7 +1066,7 @@ def AcceptInstance(instance, info, target): msg = "Failed to accept instance" logging.exception(msg) return (False, '%s: %s' % (msg, err)) - return (True, "Accept successfull") + return (True, "Accept successful") def FinalizeMigration(instance, info, success): @@ -1092,7 +1114,7 @@ def MigrateInstance(instance, target, live): msg = "Failed to migrate instance" logging.exception(msg) return (False, "%s: %s" % (msg, err)) - return (True, "Migration successfull") + return (True, "Migration successful") def BlockdevCreate(disk, size, owner, on_primary, info): @@ -1285,7 +1307,7 @@ def BlockdevAssemble(disk, owner, as_primary): def BlockdevShutdown(disk): """Shut down a block device. - First, if the device is assembled (Attach() is successfull), then + First, if the device is assembled (Attach() is successful), then the device is shutdown. Then the children of the device are shutdown. @@ -1403,7 +1425,7 @@ def BlockdevGetmirrorstatus(disks): def _RecursiveFindBD(disk): """Check if a device is activated. - If so, return informations about the real device. + If so, return information about the real device. @type disk: L{objects.Disk} @param disk: the disk object we need to find @@ -1423,7 +1445,7 @@ def _RecursiveFindBD(disk): def BlockdevFind(disk): """Check if a device is activated. - If it is, return informations about the real device. + If it is, return information about the real device. @type disk: L{objects.Disk} @param disk: the disk to find @@ -1442,6 +1464,32 @@ def BlockdevFind(disk): return (True, (rbd.dev_path, rbd.major, rbd.minor) + rbd.GetSyncStatus()) +def BlockdevGetsize(disks): + """Computes the size of the given disks. + + If a disk is not found, returns None instead. + + @type disks: list of L{objects.Disk} + @param disks: the list of disk to compute the size for + @rtype: list + @return: list with elements None if the disk cannot be found, + otherwise the size + + """ + result = [] + for cf in disks: + try: + rbd = _RecursiveFindBD(cf) + except errors.BlockDeviceError, err: + result.append(None) + continue + if rbd is None: + result.append(None) + else: + result.append(rbd.GetActualSize()) + return result + + def UploadFile(file_name, data, mode, uid, gid, atime, mtime): """Write a file to the filesystem. @@ -1472,14 +1520,7 @@ def UploadFile(file_name, data, mode, uid, gid, atime, mtime): file_name) return False - allowed_files = [ - constants.CLUSTER_CONF_FILE, - constants.ETC_HOSTS, - constants.SSH_KNOWN_HOSTS_FILE, - constants.VNC_PASSWORD_FILE, - ] - - if file_name not in allowed_files: + if file_name not in _ALLOWED_UPLOAD_FILES: logging.error("Filename passed to UploadFile not in allowed" " upload targets: '%s'", file_name) return False @@ -1812,8 +1853,8 @@ def ExportSnapshot(disk, dest_node, instance, cluster_name, idx): # the target command is built out of three individual commands, # which are joined by pipes; we check each individual command for # valid parameters - expcmd = utils.BuildShellCmd("cd %s; %s 2>%s", inst_os.path, - export_script, logfile) + expcmd = utils.BuildShellCmd("set -e; set -o pipefail; cd %s; %s 2>%s", + inst_os.path, export_script, logfile) comprcmd = "gzip" @@ -1826,7 +1867,7 @@ def ExportSnapshot(disk, dest_node, instance, cluster_name, idx): # all commands have been checked, so we're safe to combine them command = '|'.join([expcmd, comprcmd, utils.ShellQuoteArgs(remotecmd)]) - result = utils.RunCmd(command, env=export_env) + result = utils.RunCmd(["bash", "-c", command], env=export_env) if result.failed: logging.error("os snapshot export command '%s' returned error: %s" @@ -2036,7 +2077,7 @@ def BlockdevRename(devlist): # but we don't have the owner here - maybe parse from existing # cache? for now, we only lose lvm data when we rename, which # is less critical than DRBD or MD - except errors.BlockDeviceError, err: + except errors.BlockDeviceError: logging.exception("Can't rename device '%s' to '%s'", dev, unique_id) result = False return result @@ -2106,7 +2147,7 @@ def RemoveFileStorageDir(file_storage_dir): @param file_storage_dir: the directory we should cleanup @rtype: tuple (success,) @return: tuple of one element, C{success}, denoting - whether the operation was successfull + whether the operation was successful """ file_storage_dir = _TransformFileStorageDir(file_storage_dir) @@ -2121,7 +2162,7 @@ def RemoveFileStorageDir(file_storage_dir): # deletes dir only if empty, otherwise we want to return False try: os.rmdir(file_storage_dir) - except OSError, err: + except OSError: logging.exception("Cannot remove file storage directory '%s'", file_storage_dir) result = False, @@ -2150,7 +2191,7 @@ def RenameFileStorageDir(old_file_storage_dir, new_file_storage_dir): if os.path.isdir(old_file_storage_dir): try: os.rename(old_file_storage_dir, new_file_storage_dir) - except OSError, err: + except OSError: logging.exception("Cannot rename '%s' to '%s'", old_file_storage_dir, new_file_storage_dir) result = False, @@ -2458,8 +2499,6 @@ class HooksRunner(object): on the master side. """ - RE_MASK = re.compile("^[a-zA-Z0-9_-]+$") - def __init__(self, hooks_base_dir=None): """Constructor for hooks runner. @@ -2556,7 +2595,7 @@ class HooksRunner(object): dir_name = "%s/%s" % (self._BASE_DIR, subdir) try: dir_contents = utils.ListVisibleFiles(dir_name) - except OSError, err: + except OSError: # FIXME: must log output in case of failures return rr @@ -2566,7 +2605,7 @@ class HooksRunner(object): for relname in dir_contents: fname = os.path.join(dir_name, relname) if not (os.path.isfile(fname) and os.access(fname, os.X_OK) and - self.RE_MASK.match(relname) is not None): + constants.EXT_PLUGIN_MASK.match(relname) is not None): rrval = constants.HKR_SKIP output = "" else: @@ -2679,7 +2718,7 @@ class DevCacheManager(object): fdata = "%s %s %s\n" % (str(owner), state, iv_name) try: utils.WriteFile(fpath, data=fdata) - except EnvironmentError, err: + except EnvironmentError: logging.exception("Can't update bdev cache for %s", dev_path) @classmethod @@ -2701,5 +2740,5 @@ class DevCacheManager(object): fpath = cls._ConvertPath(dev_path) try: utils.RemoveFile(fpath) - except EnvironmentError, err: + except EnvironmentError: logging.exception("Can't update bdev cache for %s", dev_path)