Merge pull request #167838 from tljuniper/test-driver-pipefail-fix

nixos/test-driver: shellopts with execute + timeout

authored by Jacek Galowicz and committed by GitHub 2656cb99 ab83c5d7

+87 -51
+25 -14
nixos/doc/manual/development/writing-nixos-tests.section.md
··· 159 159 `execute` 160 160 161 161 : Execute a shell command, returning a list `(status, stdout)`. 162 + 163 + Commands are run with `set -euo pipefail` set: 164 + 165 + - If several commands are separated by `;` and one fails, the 166 + command as a whole will fail. 167 + 168 + - For pipelines, the last non-zero exit status will be returned 169 + (if there is one; otherwise zero will be returned). 170 + 171 + - Dereferencing unset variables fails the command. 172 + 173 + - It will wait for stdout to be closed. 174 + 162 175 If the command detaches, it must close stdout, as `execute` will wait 163 176 for this to consume all output reliably. This can be achieved by 164 177 redirecting stdout to stderr `>&2`, to `/dev/console`, `/dev/null` or 165 178 a file. Examples of detaching commands are `sleep 365d &`, where the 166 179 shell forks a new process that can write to stdout and `xclip -i`, where 167 180 the `xclip` command itself forks without closing stdout. 181 + 168 182 Takes an optional parameter `check_return` that defaults to `True`. 169 183 Setting this parameter to `False` will not check for the return code 170 184 and return -1 instead. This can be used for commands that shut down 171 185 the VM and would therefore break the pipe that would be used for 172 186 retrieving the return code. 173 187 188 + A timeout for the command can be specified (in seconds) using the optional 189 + `timeout` parameter, e.g., `execute(cmd, timeout=10)` or 190 + `execute(cmd, timeout=None)`. The default is 900 seconds. 191 + 174 192 `succeed` 175 193 176 194 : Execute a shell command, raising an exception if the exit status is 177 - not zero, otherwise returning the standard output. Commands are run 178 - with `set -euo pipefail` set: 179 - 180 - - If several commands are separated by `;` and one fails, the 181 - command as a whole will fail. 182 - 183 - - For pipelines, the last non-zero exit status will be returned 184 - (if there is one, zero will be returned otherwise). 185 - 186 - - Dereferencing unset variables fail the command. 187 - 188 - - It will wait for stdout to be closed. See `execute` for the 189 - implications. 195 + not zero, otherwise returning the standard output. Similar to `execute`, 196 + except that the timeout is `None` by default. See `execute` for details on 197 + command execution. 190 198 191 199 `fail` 192 200 ··· 196 204 `wait_until_succeeds` 197 205 198 206 : Repeat a shell command with 1-second intervals until it succeeds. 207 + Has a default timeout of 900 seconds which can be modified, e.g. 208 + `wait_until_succeeds(cmd, timeout=10)`. See `execute` for details on 209 + command execution. 199 210 200 211 `wait_until_fails` 201 212 202 - : Repeat a shell command with 1-second intervals until it fails. 213 + : Like `wait_until_succeeds`, but repeating the command until it fails. 203 214 204 215 `wait_for_unit` 205 216
+53 -35
nixos/doc/manual/from_md/development/writing-nixos-tests.section.xml
··· 274 274 <listitem> 275 275 <para> 276 276 Execute a shell command, returning a list 277 - <literal>(status, stdout)</literal>. If the command 278 - detaches, it must close stdout, as 279 - <literal>execute</literal> will wait for this to consume all 280 - output reliably. This can be achieved by redirecting stdout 281 - to stderr <literal>&gt;&amp;2</literal>, to 282 - <literal>/dev/console</literal>, 283 - <literal>/dev/null</literal> or a file. Examples of 284 - detaching commands are <literal>sleep 365d &amp;</literal>, 285 - where the shell forks a new process that can write to stdout 286 - and <literal>xclip -i</literal>, where the 287 - <literal>xclip</literal> command itself forks without 288 - closing stdout. Takes an optional parameter 289 - <literal>check_return</literal> that defaults to 290 - <literal>True</literal>. Setting this parameter to 291 - <literal>False</literal> will not check for the return code 292 - and return -1 instead. This can be used for commands that 293 - shut down the VM and would therefore break the pipe that 294 - would be used for retrieving the return code. 277 + <literal>(status, stdout)</literal>. 295 278 </para> 296 - </listitem> 297 - </varlistentry> 298 - <varlistentry> 299 - <term> 300 - <literal>succeed</literal> 301 - </term> 302 - <listitem> 303 279 <para> 304 - Execute a shell command, raising an exception if the exit 305 - status is not zero, otherwise returning the standard output. 306 280 Commands are run with <literal>set -euo pipefail</literal> 307 281 set: 308 282 </para> ··· 317 291 <listitem> 318 292 <para> 319 293 For pipelines, the last non-zero exit status will be 320 - returned (if there is one, zero will be returned 321 - otherwise). 294 + returned (if there is one; otherwise zero will be 295 + returned). 322 296 </para> 323 297 </listitem> 324 298 <listitem> 325 299 <para> 326 - Dereferencing unset variables fail the command. 300 + Dereferencing unset variables fails the command. 327 301 </para> 328 302 </listitem> 329 303 <listitem> 330 304 <para> 331 - It will wait for stdout to be closed. See 332 - <literal>execute</literal> for the implications. 305 + It will wait for stdout to be closed. 333 306 </para> 334 307 </listitem> 335 308 </itemizedlist> 309 + <para> 310 + If the command detaches, it must close stdout, as 311 + <literal>execute</literal> will wait for this to consume all 312 + output reliably. This can be achieved by redirecting stdout 313 + to stderr <literal>&gt;&amp;2</literal>, to 314 + <literal>/dev/console</literal>, 315 + <literal>/dev/null</literal> or a file. Examples of 316 + detaching commands are <literal>sleep 365d &amp;</literal>, 317 + where the shell forks a new process that can write to stdout 318 + and <literal>xclip -i</literal>, where the 319 + <literal>xclip</literal> command itself forks without 320 + closing stdout. 321 + </para> 322 + <para> 323 + Takes an optional parameter <literal>check_return</literal> 324 + that defaults to <literal>True</literal>. Setting this 325 + parameter to <literal>False</literal> will not check for the 326 + return code and return -1 instead. This can be used for 327 + commands that shut down the VM and would therefore break the 328 + pipe that would be used for retrieving the return code. 329 + </para> 330 + <para> 331 + A timeout for the command can be specified (in seconds) 332 + using the optional <literal>timeout</literal> parameter, 333 + e.g., <literal>execute(cmd, timeout=10)</literal> or 334 + <literal>execute(cmd, timeout=None)</literal>. The default 335 + is 900 seconds. 336 + </para> 337 + </listitem> 338 + </varlistentry> 339 + <varlistentry> 340 + <term> 341 + <literal>succeed</literal> 342 + </term> 343 + <listitem> 344 + <para> 345 + Execute a shell command, raising an exception if the exit 346 + status is not zero, otherwise returning the standard output. 347 + Similar to <literal>execute</literal>, except that the 348 + timeout is <literal>None</literal> by default. See 349 + <literal>execute</literal> for details on command execution. 350 + </para> 336 351 </listitem> 337 352 </varlistentry> 338 353 <varlistentry> ··· 353 368 <listitem> 354 369 <para> 355 370 Repeat a shell command with 1-second intervals until it 356 - succeeds. 371 + succeeds. Has a default timeout of 900 seconds which can be 372 + modified, e.g. 373 + <literal>wait_until_succeeds(cmd, timeout=10)</literal>. See 374 + <literal>execute</literal> for details on command execution. 357 375 </para> 358 376 </listitem> 359 377 </varlistentry> ··· 363 381 </term> 364 382 <listitem> 365 383 <para> 366 - Repeat a shell command with 1-second intervals until it 367 - fails. 384 + Like <literal>wait_until_succeeds</literal>, but repeating 385 + the command until it fails. 368 386 </para> 369 387 </listitem> 370 388 </varlistentry>
+9 -2
nixos/lib/test-driver/test_driver/machine.py
··· 526 526 self.run_callbacks() 527 527 self.connect() 528 528 529 + # Always run command with shell opts 530 + command = f"set -euo pipefail; {command}" 531 + 532 + timeout_str = "" 529 533 if timeout is not None: 530 - command = "timeout {} sh -c {}".format(timeout, shlex.quote(command)) 534 + timeout_str = f"timeout {timeout}" 535 + 536 + out_command = ( 537 + f"{timeout_str} sh -c {shlex.quote(command)} | (base64 --wrap 0; echo)\n" 538 + ) 531 539 532 - out_command = f"( set -euo pipefail; {command} ) | (base64 --wrap 0; echo)\n" 533 540 assert self.shell 534 541 self.shell.send(out_command.encode()) 535 542