Package ClusterShell :: Module Defaults
[hide private]
[frames] | no frames]

Source Code for Module ClusterShell.Defaults

  1  # 
  2  # Copyright (C) 2015-2016 Stephane Thiell <sthiell@stanford.edu> 
  3  # 
  4  # This file is part of ClusterShell. 
  5  # 
  6  # ClusterShell is free software; you can redistribute it and/or 
  7  # modify it under the terms of the GNU Lesser General Public 
  8  # License as published by the Free Software Foundation; either 
  9  # version 2.1 of the License, or (at your option) any later version. 
 10  # 
 11  # ClusterShell is distributed in the hope that it will be useful, 
 12  # but WITHOUT ANY WARRANTY; without even the implied warranty of 
 13  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU 
 14  # Lesser General Public License for more details. 
 15  # 
 16  # You should have received a copy of the GNU Lesser General Public 
 17  # License along with ClusterShell; if not, write to the Free Software 
 18  # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 
 19   
 20  """ 
 21  ClusterShell Defaults module. 
 22   
 23  Manage library defaults. 
 24  """ 
 25   
 26  # Imported early 
 27  # Should not import any other ClusterShell modules when loaded 
 28  from ConfigParser import ConfigParser, NoOptionError, NoSectionError 
 29  import os 
 30  import sys 
 31   
 32   
 33  # 
 34  # defaults.conf sections 
 35  # 
 36  CFG_SECTION_TASK_DEFAULT = 'task.default' 
 37  CFG_SECTION_TASK_INFO = 'task.info' 
 38   
 39  # 
 40  # Functions 
 41  # 
42 -def _task_print_debug(task, line):
43 """Default task debug printing function.""" 44 print line
45
46 -def _load_workerclass(workername):
47 """ 48 Return the class pointer matching `workername`. 49 50 The module is loaded if not done yet. 51 """ 52 modname = "ClusterShell.Worker.%s" % workername.capitalize() 53 54 # Do not iterate over sys.modules but use .keys() to avoid RuntimeError 55 if modname.lower() not in [mod.lower() for mod in sys.modules.keys()]: 56 # Import module if not yet loaded 57 __import__(modname) 58 59 # Get the class pointer 60 return sys.modules[modname].WORKER_CLASS
61
62 -def _local_workerclass(defaults):
63 """Return default local worker class.""" 64 return _load_workerclass(defaults.local_workername)
65
66 -def _distant_workerclass(defaults):
67 """Return default distant worker class.""" 68 return _load_workerclass(defaults.distant_workername)
69
70 -def config_paths(config_name):
71 """Return default path list for a ClusterShell config file name.""" 72 return ['/etc/clustershell/%s' % config_name, # system-wide config file 73 # default pip --user config file 74 os.path.expanduser('~/.local/etc/clustershell/%s' % config_name), 75 # per-user config (top override) 76 os.path.join(os.environ.get('XDG_CONFIG_HOME', 77 os.path.expanduser('~/.config')), 78 'clustershell', config_name)]
79 80 # 81 # Classes 82 #
83 -class Defaults(object):
84 """ 85 Class used to manipulate ClusterShell defaults. 86 87 The following attributes may be read at any time and also changed 88 programmatically, for most of them **before** ClusterShell objects 89 are initialized (like Task): 90 91 * stderr (boolean; default is ``False``) 92 * stdout_msgtree (boolean; default is ``True``) 93 * stderr_msgtree (boolean; default is ``True``) 94 * engine (string; default is ``'auto'``) 95 * port_qlimit (integer; default is ``100``) 96 * local_workername (string; default is ``'exec'``) 97 * distant_workername (string; default is ``'ssh'``) 98 * debug (boolean; default is ``False``) 99 * print_debug (function; default is internal) 100 * fanout (integer; default is ``64``) 101 * grooming_delay (float; default is ``0.25``) 102 * connect_timeout (float; default is ``10``) 103 * command_timeout (float; default is ``0``) 104 105 Example of use:: 106 107 >>> from ClusterShell.Defaults import DEFAULTS 108 >>> from ClusterShell.Task import task_self 109 >>> # Change default distant worker to rsh (WorkerRsh) 110 ... DEFAULTS.distant_workername = 'rsh' 111 >>> task = task_self() 112 >>> task.run("uname -r", nodes="cs[01-03]") 113 <ClusterShell.Worker.Rsh.WorkerRsh object at 0x1f4a410> 114 >>> list((str(msg), nodes) for msg, nodes in task.iter_buffers()) 115 [('3.10.0-229.7.2.el7.x86_64', ['cs02', 'cs01', 'cs03'])] 116 117 118 The library default values of all of the above attributes may be changed 119 using the defaults.conf configuration file, except for *print_debug* 120 (cf. :ref:`defaults-config`). An example defaults.conf file should be 121 included with ClusterShell. Remember that this could affect all 122 applications using ClusterShell. 123 """ 124 125 # 126 # Default values for task "default" sync dict 127 # 128 _TASK_DEFAULT = {"stderr" : False, 129 "stdout_msgtree" : True, 130 "stderr_msgtree" : True, 131 "engine" : 'auto', 132 "port_qlimit" : 100, 133 "auto_tree" : True, 134 "local_workername" : 'exec', 135 "distant_workername" : 'ssh'} 136 137 # 138 # Datatype converters for task_default 139 # 140 _TASK_DEFAULT_CONVERTERS = {"stderr" : ConfigParser.getboolean, 141 "stdout_msgtree" : ConfigParser.getboolean, 142 "stderr_msgtree" : ConfigParser.getboolean, 143 "engine" : ConfigParser.get, 144 "port_qlimit" : ConfigParser.getint, 145 "auto_tree" : ConfigParser.getboolean, 146 "local_workername" : ConfigParser.get, 147 "distant_workername" : ConfigParser.get} 148 149 # 150 # Default values for task "info" async dict 151 # 152 _TASK_INFO = {"debug" : False, 153 "print_debug" : _task_print_debug, 154 "fanout" : 64, 155 "grooming_delay" : 0.25, 156 "connect_timeout" : 10, 157 "command_timeout" : 0} 158 159 # 160 # Datatype converters for task_info 161 # 162 _TASK_INFO_CONVERTERS = {"debug" : ConfigParser.getboolean, 163 "fanout" : ConfigParser.getint, 164 "grooming_delay" : ConfigParser.getfloat, 165 "connect_timeout" : ConfigParser.getfloat, 166 "command_timeout" : ConfigParser.getfloat} 167 168 # 169 # Black list of info keys whose values cannot safely be propagated 170 # in tree mode 171 # 172 _TASK_INFO_PKEYS_BL = ['engine', 'print_debug'] 173
174 - def __init__(self, filenames):
175 """Initialize Defaults from config filenames""" 176 177 self._task_default = self._TASK_DEFAULT.copy() 178 self._task_info = self._TASK_INFO.copy() 179 self._task_info_pkeys_bl = list(self._TASK_INFO_PKEYS_BL) 180 181 config = ConfigParser() 182 parsed = config.read(filenames) 183 184 if parsed: 185 self._parse_config(config)
186
187 - def _parse_config(self, config):
188 """parse config""" 189 190 # task_default overrides 191 for key, conv in self._TASK_DEFAULT_CONVERTERS.items(): 192 try: 193 self._task_default[key] = conv(config, CFG_SECTION_TASK_DEFAULT, 194 key) 195 except (NoSectionError, NoOptionError): 196 pass 197 198 # task_info overrides 199 for key, conv in self._TASK_INFO_CONVERTERS.items(): 200 try: 201 self._task_info[key] = conv(config, CFG_SECTION_TASK_INFO, key) 202 except (NoSectionError, NoOptionError): 203 pass
204
205 - def __getattr__(self, name):
206 """Defaults attribute lookup""" 207 if name in self._task_default: 208 return self._task_default[name] 209 elif name in self._task_info: 210 return self._task_info[name] 211 raise AttributeError(name)
212
213 - def __setattr__(self, name, value):
214 """Defaults attribute assignment""" 215 if name in ('_task_default', '_task_info', '_task_info_pkeys_bl'): 216 object.__setattr__(self, name, value) 217 elif name in self._task_default: 218 self._task_default[name] = value 219 elif name in self._task_info: 220 self._task_info[name] = value 221 else: 222 raise AttributeError(name)
223 224 # 225 # Globally accessible Defaults object 226 # 227 DEFAULTS = Defaults(config_paths('defaults.conf')) 228