`multipass restart` should just start instances if they're not running
Steps:
- launch an instance
- stop it or suspend
- try to
restartit
Expected:
- instance gets started
Current:
- error:
restart failed: instance "preferable-phoenix" is not running
Hmm, I kind of disagree with this. To me, restart implies something is already running and you want to turn it off and back on again so something is in a known good state. Otherwise, if something is already shutdown, then it's not restarting it, it's starting it.
I think there should be a distinction between start and restart in this sense in that an instance needs to be running in order for it to be restarted.
I basically agree with @townsend2010. In response to @Saviq's call for writing down our thoughts until we meet, here is a summary of the main points I see:
- Fail-fast: point the error in the user's assumptions ASAP. When a user asks for a restart of a stopped instance, he is wrongly assuming the instance is running. We should call his attention to that rather than implicitly validating his mental state.
- I recognize idempotence is contrary to this, but it is not in question here, as restart is by definition never idempotent.
- If
restartwas able to start stopped instances, it would makestartmostly redundant: there would be no practical use case forstartthat could not be accomplished withrestartinstead.- A separate command only for the "idempotence" case sounds like a confusing sort of alias. If restart is only different from start in that it is not idempotent, then it should not be a separate command, it should be a flag: on this occasion, go through the starting process again even if the end-state is the same:
multipass start --restart [...]
- A separate command only for the "idempotence" case sounds like a confusing sort of alias. If restart is only different from start in that it is not idempotent, then it should not be a separate command, it should be a flag: on this occasion, go through the starting process again even if the end-state is the same:
- Currently,
restartis technically different from astart/stopsequence: it is implemented withsudo rebootwithin the machine, rather than outside steering.- whether this should be an implementation detail or part of the interface is unclear to me, but I suppose there could be ways to configure a VM to do something on reboot and not on stop/start (e.g. at the limit, pointing reboot to a different binary would achieve that)
@gerboland @matthewpaulthomas could you weigh in here please?
I’m not confident in recommending one behaviour or another, because I don’t know how common each of these use cases would be:
- “I want to make sure that instance X is running”
- “I want to start instance X, but if it was already running that’s an error I need to deal with first”
If both would be common, then, are there parallels with the syntax of popular existing commands? ssh, screen, tmux, apache2/apachectl…
It's a mix, I'm afraid… I'd say the two usecases are more like:
- "I want this instance to be stopped and started again"
- "I want this instance to be freshly booted"
IMO the latter is most often the user's intent. They don't care what the state is of the instance, rather that after this operation completes, it is freshly started.
For reference:
These do start if not already running:
$ man apachectl # apache
…
restart Restarts the Apache daemon by sending it a SIGHUP. If the daemon is not running, it is started.
$ man systemctl # services
…
restart PATTERN...
Stop and then start one or more units specified on the command line. If the units are not running yet, they will be started.
$ docker restart --help # docker containers
…
Restart one or more containers
The ones below error out if not already running:
$ lxc restart --help # LXD containers
…
Restart containers
$ virsh reset --help # libvirt instances
…
Reset the target domain as if by power button
$ lxc-stop --help # LXC containers
…
-r, --reboot reboot the container
It's better of telling the user to use multipass start <INSTANCE_NAME> after printing out the error.
@amylily1011, what's your take on this one?
By definition, I totally agree with @townsend2010. However, from a UX perspective we can make this more seamless.
IMO, it is quite often that a user would think that they need to restart the instance because they have started it. Even though, the instance has been suspended or stopped due to being inactive or multiple other reasons, people don't usually know the latest status on top of their heads, as opposed to desktop UI.
I see this as an opportunity to make the the output statement clear.
Scenario 1:
- current state: suspended/stop
- user tries to restart (multipass restart <INSTANCE_NAME>)
- output: ....Current state of this instance is suspended. Initiating the start command.
Scenario 2:
- current state: running
- user tries to restart
- output: ....Current state of this instance is running. Restarting this instance.
Scenario 3:
- current state: suspended
- user tries to restart
- output: .....Current state of this instance is suspended. Would you like to start the instance? [Y/N]
if [Y] -> multipass initiates the start command if [N] -> returns nothing
In a situation where we need to consider security as a part of the interaction such as when upgrading requires backing up the DB or when things can break, I would suggest scenario 3 as the solution.
However, it seems that restarting does not require that kind of attention, so I would suggest scenario 1 as a solution. Because, this will allow users to understand the state and instead of getting a slap for making a mistake, we are directing the interaction to the right intent.
@amylily1011 Makes sense. Would you recommend option 1 in non-interactive mode as well (as when multipass is called from a script)?
I don't know if this is something you want to include in your audit. I am removing the needs triage label, but feel free to adjust the priority.
@ricab can you provide more context for the scripting scenario? For instance, how does option 1 affect scripting outputs. My current assumption is that option 1 can be part of the scripting experience as it does not seem to affect the output differently. But, I don't know enough cases about how this might break the script.
Hi @amylily1011
@ricab can you provide more context for the scripting scenario?
OK, imagine a situation where a user has a script that calls multipass commands, or where multipass is called from terraform or MCP. Something where there is no user reading the output before typing the next command (or answering questions).
If the person writing the script/tool/whatever expected "restart" to "reboot", they would not be alerted in time. For example:
$ ... # we have some VM foo
$ change-things-on-the-host # change the context of the VM in a way that requires reboot
$ multipass restart foo # if it was suspended, it won't reboot, but there is no error so the script continues
$ multipass exec foo -- this-and-that # something that assumes the VM rebooted
$ ... # more
That said, it's probably not a big deal. We just need to document properly and people will need to learn that restart != stop+start. WDYT?
Based on our discussion today (@ricab )
- We should stick to the principle of one command: one purpose. (Start is starting the instance and restart is rebooting the instance.)
- In the case of restart, by definition it means reboot. We think that scenario 3 with adjustments makes the most sense.
Fix suggestions for the CLI:
- current state: suspended
- user tries to restart
- output: .....Current state of this instance is suspended. Would you like to reboot the instance? [default: Y /N] if [Y] -> multipass initiates reboot, it starts then restart. if [N] -> message: Use the start command to start this instance.
For scripting case: We will assume the by default that it's a "No" then the output will share the error message so the user will need to fix the script to start the instance.
[Todo: @amylily1011 to add this in the audit spec.]
@amylily1011, I forgot to ask you at the end there: do you think the command should be renamed to reboot as well? IDK myself TBH. On the one hand, it might help clarify ambiguity. On the other, it might look out of place with respect to start (which isn't called boot).
@Saviq, I noticed your reaction there :) Feel free to discuss with Amy too. Personally I am fine with any choice at this point really, as long as it is properly documented and the output is clear
@Saviq if I missed something, please chime in. The problem I see is that when you are in the suspended state, the idea is you don't want to reboot, but instead want to resume it to running state. If we merge these two purposes together, it becomes very confusing for users.
@ricab I think changing the command name is too disruptive at this stage. Unless we have a clear idea/direction that we want to have restart and reboot as two separate commands and that they are created for different purposes. At this point, it seems the restart command is interpreted as reboot and the start command is boot.
@amylily1011 @ricab just kidding, it's just I always considered the CLI an end-user interface - not a scripting one, so that argument doesn't particularly sit with me. If you are scripting around it, you should check the instance status before you try and restart it - and if you've been doing something with the instance up to that point, why would it be suspended when you try and restart it?
Y'all's call in the end! :)
An alternative would be to store all your multipass settings and modify the path where it saves it's VMs. Then you can scan the folder names and use multipass start <VM>
Then use installcommand to install the shell script in /use/share