1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 """
22 Common ClusterShell CLI OptionParser
23
24 With few exceptions, ClusterShell command-lines share most option
25 arguments. This module provides a common OptionParser class.
26 """
27
28 from copy import copy
29 import optparse
30
31 from ClusterShell import __version__
32 from ClusterShell.Engine.Factory import PreferredEngine
33 from ClusterShell.CLI.Display import THREE_CHOICES
34
35
37 """type-checker function for autostep"""
38 try:
39 if '%' in value:
40 return float(value[:-1]) / 100.0
41 return int(value)
42 except ValueError:
43 if value == 'auto':
44 return value
45 error_fmt = "option %s: invalid value: %r, should be node count, " \
46 "node percentage or 'auto'"
47 raise optparse.OptionValueError(error_fmt % (opt, value))
48
50 """type-checker function for safestring"""
51 try:
52 safestr = str(value)
53
54 if not safestr or safestr.startswith('-'):
55 raise ValueError()
56 return safestr
57 except ValueError:
58 raise optparse.OptionValueError(
59 "option %s: invalid value: %r" % (opt, value))
60
61
68
70 """Derived OptionParser for all CLIs"""
71
73 """Initialize ClusterShell CLI OptionParser"""
74 optparse.OptionParser.__init__(self, usage,
75 version="%%prog %s" % __version__,
76 option_class=Option,
77 **kwargs)
78
79
80 self.disable_interspersed_args()
81
82
83 self.add_option("-s", "--groupsource", action="store",
84 type="safestring", dest="groupsource",
85 help="optional groups.conf(5) group source to use")
86
88 """Install config options override"""
89 self.add_option("-O", "--option", action="append", metavar="KEY=VALUE",
90 dest="option", default=[],
91 help="override any key=value %s options" % filename)
92
94 """Install nodes selection options"""
95 optgrp = optparse.OptionGroup(self, "Selecting target nodes")
96 optgrp.add_option("-w", action="append", type="safestring",
97 dest="nodes", help="nodes where to run the command")
98 optgrp.add_option("-x", action="append", type="safestring",
99 dest="exclude", metavar="NODES",
100 help="exclude nodes from the node list")
101 optgrp.add_option("-a", "--all", action="store_true", dest="nodes_all",
102 help="run command on all nodes")
103 optgrp.add_option("-g", "--group", action="append", type="safestring",
104 dest="group", help="run command on a group of nodes")
105 optgrp.add_option("-X", action="append", dest="exgroup",
106 metavar="GROUP", type="safestring",
107 help="exclude nodes from this group")
108 optgrp.add_option("-E", "--engine", action="store", dest="engine",
109 choices=["auto"] + PreferredEngine.engines.keys(),
110 default="auto", help=optparse.SUPPRESS_HELP)
111 optgrp.add_option("--hostfile", "--machinefile", action="append",
112 dest="hostfile", default=[], metavar='FILE',
113 help="path to file containing a list of target hosts")
114 optgrp.add_option("--topology", action="store", dest="topofile",
115 default=None, metavar='FILE',
116 help="topology configuration file to use for tree "
117 "mode")
118 optgrp.add_option("--pick", action="store", dest="pick",
119 metavar="N", type="int",
120 help="pick N node(s) at random in nodeset")
121 self.add_option_group(optgrp)
122
123 - def install_display_options(self,
124 debug_option=True,
125 verbose_options=False,
126 separator_option=False,
127 dshbak_compat=False,
128 msgtree_mode=False):
129 """Install options needed by Display class"""
130 optgrp = optparse.OptionGroup(self, "Output behaviour")
131 if verbose_options:
132 optgrp.add_option("-q", "--quiet", action="store_true",
133 dest="quiet", help="be quiet, print essential output only")
134 optgrp.add_option("-v", "--verbose", action="store_true",
135 dest="verbose", help="be verbose, print informative messages")
136 if debug_option:
137 optgrp.add_option("-d", "--debug", action="store_true",
138 dest="debug",
139 help="output more messages for debugging purpose")
140 optgrp.add_option("-G", "--groupbase", action="store_true",
141 dest="groupbase", default=False,
142 help="do not display group source prefix")
143 optgrp.add_option("-L", action="store_true", dest="line_mode",
144 help="disable header block and order output by nodes")
145 optgrp.add_option("-N", action="store_false", dest="label",
146 default=True, help="disable labeling of command line")
147 if dshbak_compat:
148 optgrp.add_option("-b", "-c", "--dshbak", action="store_true",
149 dest="gather", help="gather nodes with same output")
150 else:
151 optgrp.add_option("-P", "--progress", action="store_true",
152 dest="progress", help="show progress during command execution")
153 optgrp.add_option("-b", "--dshbak", action="store_true",
154 dest="gather", help="gather nodes with same output")
155 optgrp.add_option("-B", action="store_true", dest="gatherall",
156 default=False, help="like -b but including standard error")
157 optgrp.add_option("-r", "--regroup", action="store_true",
158 dest="regroup", default=False,
159 help="fold nodeset using node groups")
160
161 if separator_option:
162 optgrp.add_option("-S", "--separator", action="store",
163 dest="separator", default=':',
164 help="node / line content separator string "
165 "(default: ':')")
166 else:
167 optgrp.add_option("-S", action="store_true", dest="maxrc",
168 help="return the largest of command return codes")
169
170 if msgtree_mode:
171
172 optgrp.add_option("-F", "--fast", action="store_true",
173 dest="fast_mode",
174 help="faster but memory hungry mode")
175 optgrp.add_option("-T", "--tree", action="store_true",
176 dest="trace_mode",
177 help="message tree trace mode")
178 optgrp.add_option("--interpret-keys", action="store",
179 dest="interpret_keys", choices=THREE_CHOICES,
180 default=THREE_CHOICES[-1], help="whether to "
181 "interpret keys (never, always or auto)")
182
183 optgrp.add_option("--color", action="store", dest="whencolor",
184 choices=THREE_CHOICES, help="whether to use ANSI "
185 "colors (never, always or auto)")
186 optgrp.add_option("--diff", action="store_true", dest="diff",
187 help="show diff between gathered outputs")
188 self.add_option_group(optgrp)
189
191 """special callback method for copy and rcopy toggles"""
192
193 self.enable_interspersed_args()
194
195 setattr(parser.values, option.dest, True)
196
198 """Install file copying specific options"""
199 optgrp = optparse.OptionGroup(self, "File copying")
200 optgrp.add_option("-c", "--copy", action="callback", dest="copy",
201 callback=self._copy_callback,
202 help="copy local file or directory to remote nodes")
203 optgrp.add_option("--rcopy", action="callback", dest="rcopy",
204 callback=self._copy_callback,
205 help="copy file or directory from remote nodes")
206 optgrp.add_option("--dest", action="store", dest="dest_path",
207 help="destination file or directory on the nodes")
208 optgrp.add_option("-p", action="store_true", dest="preserve_flag",
209 help="preserve modification times and modes")
210 self.add_option_group(optgrp)
211
212
214 """Install engine/connector (ssh, ...) options"""
215 optgrp = optparse.OptionGroup(self, "Connection options")
216 optgrp.add_option("-f", "--fanout", action="store", dest="fanout",
217 help="use a specified fanout", type="int")
218
219 optgrp.add_option("--grooming", action="store", dest="grooming_delay",
220 help=optparse.SUPPRESS_HELP, type="float")
221 optgrp.add_option("-l", "--user", action="store", type="safestring",
222 dest="user", help="execute remote command as user")
223 optgrp.add_option("-o", "--options", action="store", dest="options",
224 help="can be used to give ssh options")
225 optgrp.add_option("-t", "--connect_timeout", action="store",
226 dest="connect_timeout",
227 help="limit time to connect to a node", type="float")
228 optgrp.add_option("-u", "--command_timeout", action="store",
229 dest="command_timeout",
230 help="limit time for command to run on the node",
231 type="float")
232 optgrp.add_option("-R", "--worker", action="store", dest="worker",
233 help="worker name to use for command execution "
234 "('exec', 'rsh', 'ssh', etc. default is 'ssh')")
235 optgrp.add_option("--remote", action="store", dest="remote",
236 choices=('yes', 'no'),
237 help="whether to enable remote execution: in tree "
238 "mode, 'yes' forces connections to the leaf "
239 "nodes for execution, 'no' establishes "
240 "connections up to the leaf parent nodes for "
241 "execution (default is 'yes')")
242 self.add_option_group(optgrp)
243
245 """Install nodeset commands"""
246 optgrp = optparse.OptionGroup(self, "Commands")
247 optgrp.add_option("-c", "--count", action="store_true", dest="count",
248 default=False,
249 help="show number of nodes in nodeset(s)")
250 optgrp.add_option("-e", "--expand", action="store_true", dest="expand",
251 default=False,
252 help="expand nodeset(s) to separate nodes")
253 optgrp.add_option("-f", "--fold", action="store_true", dest="fold",
254 default=False, help="fold nodeset(s) (or separate "
255 "nodes) into one nodeset")
256 optgrp.add_option("-l", "--list", action="count", dest="list",
257 default=False, help="list node groups from one "
258 "source (see -s GROUPSOURCE)")
259 optgrp.add_option("-L", "--list-all", action="count", dest="listall",
260 default=False,
261 help="list node groups from all group sources")
262 optgrp.add_option("-r", "--regroup", action="store_true",
263 dest="regroup", default=False,
264 help="fold nodes using node groups (see -s "
265 "GROUPSOURCE)")
266 optgrp.add_option("--list-sources", "--groupsources",
267 action="store_true", dest="groupsources",
268 default=False,
269 help="list all active group sources (see "
270 "groups.conf(5))")
271 self.add_option_group(optgrp)
272
274 """Install nodeset operations"""
275 optgrp = optparse.OptionGroup(self, "Operations")
276 optgrp.add_option("-x", "--exclude", action="append", dest="sub_nodes",
277 default=[], type="string",
278 help="exclude specified nodeset")
279 optgrp.add_option("-i", "--intersection", action="append",
280 dest="and_nodes", default=[], type="string",
281 help="calculate nodesets intersection")
282 optgrp.add_option("-X", "--xor", action="append", dest="xor_nodes",
283 default=[], type="string",
284 help="calculate symmetric difference between "
285 "nodesets")
286 self.add_option_group(optgrp)
287
289 """Install nodeset options"""
290 optgrp = optparse.OptionGroup(self, "Options")
291 optgrp.add_option("-a", "--all", action="store_true", dest="all",
292 help="call external node groups support to "
293 "display all nodes")
294 optgrp.add_option("--autostep", action="store", dest="autostep",
295 help="enable a-b/step style syntax when folding, "
296 "value is min node count threshold (eg. '4', "
297 "'50%' or 'auto')",
298 type="autostep")
299 optgrp.add_option("-d", "--debug", action="store_true", dest="debug",
300 help="output more messages for debugging purpose")
301 optgrp.add_option("-q", "--quiet", action="store_true", dest="quiet",
302 help="be quiet, print essential output only")
303 optgrp.add_option("-R", "--rangeset", action="store_true",
304 dest="rangeset", help="switch to RangeSet instead "
305 "of NodeSet. Useful when working on numerical "
306 "cluster ranges, eg. 1,5,18-31")
307 optgrp.add_option("-G", "--groupbase", action="store_true",
308 dest="groupbase", help="hide group source prefix "
309 "(always \"@groupname\")")
310 optgrp.add_option("-S", "--separator", action="store", dest="separator",
311 default=' ', help="separator string to use when "
312 "expanding nodesets (default: ' ')")
313 optgrp.add_option("-O", "--output-format", action="store",
314 dest="output_format", metavar='FORMAT', default='%s',
315 help="output format (default: '%s')")
316 optgrp.add_option("-I", "--slice", action="store",
317 dest="slice_rangeset",
318 help="return sliced off result", type="string")
319 optgrp.add_option("--split", action="store", dest="maxsplit",
320 help="split result into a number of subsets",
321 type="int")
322 optgrp.add_option("--contiguous", action="store_true",
323 dest="contiguous", help="split result into "
324 "contiguous subsets")
325 optgrp.add_option("--axis", action="store", dest="axis",
326 metavar="RANGESET", help="fold along these axis only "
327 "(axis 1..n for nD nodeset)")
328 optgrp.add_option("--pick", action="store", dest="pick",
329 metavar="N", type="int",
330 help="pick N node(s) at random in nodeset")
331 self.add_option_group(optgrp)
332