add qvm-restart - #470
add qvm-restart#470RandyTheOtter wants to merge 1 commit into
qvm-restart#470Conversation
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #470 +/- ##
=======================================
Coverage 76.84% 76.85%
=======================================
Files 53 54 +1
Lines 9434 9472 +38
=======================================
+ Hits 7250 7280 +30
- Misses 2184 2192 +8 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
|
That should address the issues that are obvious-ish for me to fix. Only thing left is the qvm-start issue. @marmarek it seems to me Am I missing something? |
There is a bunch of cases where qvm-start can fail. Startup timeout, not enough memory, not enough disk space, and many more. BTW #469 does refactor to make at least shutdown function reusable. You might want to wait for it to be merged, and then use the new function. |
Shouldn't it get caught here?: It returns status after the loop ends, so all start-able domains should start. They definitely do when I try a group with some of them having far too much memory to start. |
|
Right, this case might be okay. But still, invoking other tool's main from another tool, parsing arguments again etc is not a good idea. This will also create several instances of |
What's wrong with that? If anything using the same
Okay, should I create a separate pr for that, similar to Ben's |
No need for a separate PR, unless Github auto-closes this one when you rebase to a different upstream branch, and doesn't allow anyone to reopen it...
|
| ) | ||
| ) | ||
| if failed['start']: | ||
| sys.stderr.write("Failed to start domains back up:\n") |
There was a problem hiding this comment.
See parser.print_error.
There was a problem hiding this comment.
Wow that method looks useless, and requires making parser available. Why does it exist?
Regardless, I can't use it if I want to have output without "Error:" in each print. Adopted for pre-report messages.
46d45b5 to
626ae1f
Compare
|
Pylint is complaining that test lines too long, when broken apart they're less readable. |
|
Seems like |
Use |
| if not args.start: | ||
| target_domains = [ | ||
| vm for vm in target_domains | ||
| if vm.get_power_state() == "Running" |
There was a problem hiding this comment.
Change this to if vm.is_running()?
|
I have a use case for this to be in "utils" module (without expecting a command-line client), so I can easily use here (see how other actions were done): |
marmarek
left a comment
There was a problem hiding this comment.
Besides comments below, can you squash the commits (and possibly add co-authored-by tag to the commit message to retain info about Ali)?
| ) | ||
| self.app.expected_calls[ | ||
| ("some-vm", "admin.vm.Shutdown", "wait", None) | ||
| ] = b"0\x00" |
There was a problem hiding this comment.
This should be:
| ] = b"0\x00" | |
| ] = b"2\x00QubesVMNotStartedErrorDomain is powered off: 'some-vm'" |
There was a problem hiding this comment.
CurrentState responses are too long even with black -l 80, looking at the other tests it seems like I can cheat a little and mock only power_state part of the response. It fixed some failing tests as well
There was a problem hiding this comment.
Whoops, I replied to the wrong conversation...
Anyway, QubesVMNotStartedErrorDomain is wrong, shutdown doesn't fail if target is down. Correct me if it's an upcoming change I haven't seen yet, but with current admin it replies 0\x00.
| ) | ||
| self.app.expected_calls[ | ||
| ("dormant-vm", "admin.vm.Shutdown", "force+wait", None) | ||
| ] = b"0\x00" |
9e9793a to
79f3a32
Compare
| b"0\x00some-vm class=AppVM state=Running\n" | ||
| ) | ||
| self.app.expected_calls[("some-vm", "admin.vm.CurrentState", None, None)] = ( | ||
| b"0\x00some-vm mem=42069 mem_static_max=42069 cputime=1337 power_state=Running\n" |
There was a problem hiding this comment.
Example return type of admin.vm.CurrentState
% qubesd-query -e dom0 admin.vm.CurrentState dom0 | cat -A
0^@mem=4000000 mem_static_max=16000 cputime=440000000 power_state=Running% So know you know where the null is, just first character. My shell shows that there is no newline, by printing a % with reversevideo at the end.
If there were newline, it would have printed $:
% printf '\n' | cat -A
$But on your shell, if it is not customized to handle output missing newline, your prompt will be on the same line as the output like this:
% bash --norc
bash-5.2$ printf '\0' | cat -A
^@bash-5.2$If you want to see null representation and no newline without newline:
% printf '\0' | cat -A
^@%There was a problem hiding this comment.
If you want to see precise bytes, I'd recommend xxd or hexdump -C.
|
For the |
CurrentState responses are too long even with black -l 80, looking at the other tests it seems like I can cheat a little and mock only power_state part of the response. It have fixed some failing tests as well... Somehow... |
|
I was going to say that this is wrong, as you can break strings into multiple lines, but there are other tests, such as |
|
|
||
| if failed['shutdown']: | ||
| parser.print_error( | ||
| "Failed to restart domains:\n", |
There was a problem hiding this comment.
I think the word "shutdown" fits better here.
There was a problem hiding this comment.
Why? Shutdown failure implies startup failure, thus it is a restart failure.
There was a problem hiding this comment.
Restart is made of "shutdown + start". Being specific that it is the "shutdown" is to be explicit and avoid ambiguous meaning.
| ] | ||
| ) | ||
| ) | ||
| return failed |
There was a problem hiding this comment.
We have to consider that every other method using generic_action has the same return type, which this functions changes from dict[QubesVM, BaseException] to dict[str, dict[QubesVM, BaseException]]. I am not sure what to do here, I don't like inconsistencies and would like that calling any of these actions returned the same type, so we don't need separate evaluation of the result depending on the method called, but I also understand that you use it for logging in qvm_restart. Maybe you could evaluate based on known exceptions for each call, and then do a safe fallback to generic logging when the exception is not known.
There was a problem hiding this comment.
Do we have a purpose for consistency here? Exception matching looks like avoidable maintenance burden considering that we already know which instruction returns what.
There was a problem hiding this comment.
A single function that deals with all qube state wrappers. If the restart wrapper has a return signature, I'd need to create a separate handling just for that.
Ideally, there would be a parent class QubesVMShutdownError and QubesVMStartError, so that you could check if QubesVMShutdownTimeoutError or QubesMemoryError is part of which, so you would return with the same signature, and the command-line tool that intendes to log the information, would us isinstance to check hierarchy.
Co-Authored-By: Ali Mirjamali <ali@mirjamali.com>
marmarek
left a comment
There was a problem hiding this comment.
CI complains about undocumented option:
Undocumented arguments for command 'qvm-restart': '--kill, -k'
| *report_failure(failed_start), | ||
| end="" | ||
| ) | ||
|
|
There was a problem hiding this comment.
restart generator needs to be closed:
await restart.aclose()
An attempt to finalize Ali's work: #387
Closes QubesOS/qubes-issues#4747
I have decided to not handle shutdown in situ because I would like to avoid duplication