Network manager can create routes at metric aka priority above 20000.
These can stick around if they are not the best choice, or they may
disappear quickly.
Do not consider one of these routes as a valid default route for
has_network purposes.
The existing event based method of watching for has_network has a flaw.
The incoming route_change events from probert do not distinguish routes
on the same interface but a different metric, so if 2 routes on one
interface appear, we only get one event. Then if one of those routes is
removed, we will inappropriately remove this route from the
default_routes list.
Aside from the code watching the event stream, the set of default routes
is an elaborate boolean value.
Simplify the code by passing around a boolean, and when we get a
route_change event, use that to go looking again at the list of default
routes.
LP: #2004659
parameterized async tests run into cpython bug gh-101486
We use parameterized.expand, which works by creating new functions and
inserting those into the list of tests. It's a wonder this worked at
all before for the async tests.
Update the function generation to create a coroutine function, if
appropriate.
LP: #2007554
create_task has the following note:
Important: Save a reference to the result of this function, to avoid a
task disappearing mid-execution.
Convert existing usage of create_task to run_bg_task, if that
create_task is not actually storing the result.
We used to set LC_ALL=C unconditionally when executing a command. This
is a problem if we want the output of a specific command to be
translated (provided a locale definition and an actual translation exist
for the requested language).
This patch adds the clean_locale parameter, which can be used to specify
if we want the locale variable to be cleaned, to most of the helpers
that execute commands.
The value defaults to True so the default behavior is preserved.
If one wants a command to be translated, they have to explicitly pass
clean_locale=False.
Signed-off-by: Olivier Gayot <olivier.gayot@canonical.com>
calling asyncio.create_task(...) without storing a reference to the
result can lead to the task being garbage collected before it actually
executed.
https://docs.python.org/3/library/asyncio-task.html#asyncio.create_task
The documentation gives an example of a reliable way to run
fire-and-forget background tasks.
This patch adds an helper to do exactly that.
Signed-off-by: Olivier Gayot <olivier.gayot@canonical.com>
The new ConfirmationOverlay object along with the
BaseView.ask_confirmation helper can be used to open a confirmation
dialog and get back the decision from the user.
Signed-off-by: Olivier Gayot <olivier.gayot@canonical.com>
Specifying the value of subprocess.PIPE as the stdin argument of
astart_command did not have any effect. This happened because the
parameter was not forwarded to the subprocess function. The parameter
was effectively unused.
Signed-off-by: Olivier Gayot <olivier.gayot@canonical.com>
Attempting to close an overlay that does not exist is pretty much always
a bug in the code. Making not_found_ok true by default will hide obvious
bugs from us ; which is not a good thing. Perhaps more importantly, we
might just remove the wrong overlay.
Instead, we should just pass not_found_ok=True as a workaround when we
know the code is buggy and don't have time to fix the bug cleanly.
This is what happens for SSH keys import. If the import fails, we remove
the loading animation. However for answers-based runs, we do not have a
loading animation so the code bails. Let's add not_found_ok=True in this
context and we can fix the code later.
Signed-off-by: Olivier Gayot <olivier.gayot@canonical.com>
BaseView.remove_overlay() would crash with AttributeError if no overlay
was found. We now add a not_found_ok parameter (defaulting to True) that
makes the function silently return if the overlay could not be found.
Passing not_found_ok=False and catching OverlayNotFoundError can be
helpful in some scenarios to do something different if no overlay was
found.
Signed-off-by: Olivier Gayot <olivier.gayot@canonical.com>
I implemented these a long time ago to help working on parts of the ui
by allowing a way to script moving past some screens. I haven't used
them in ages, it's pretty bad code and probably a fragmentary answers
file is a better solution to the same problem. What do you think?
When executing a command via arun_command with check=True, we forge
and then raise a CalledProcessError exception if the command exits
abnormally (i.e., exit code != 0).
When doing so, we only instantiate the exception with the exit code and
the command executed. This means that we lose access to any output
captured so far. This is usually fine for stdout but stderr oftentimes
contains invaluable information to understand what caused the command to
exit abnormally.
Back in Python 3.5, stdout and stderr were introduced as new attributes
for CalledProcessError.
We now also include stdout and stderr in the CalledProcessError
instances that we forge. This allows us to access stderr (if any) when
catching the exception with:
try:
...
except CalledProcessError as exc:
print(exc.stderr)
Signed-off-by: Olivier Gayot <olivier.gayot@canonical.com>
asyncio.create_task() calls asyncio.get_running_loop() under the hood so
there is no need to call get_running_loop() ourselves if the sole
purpose is to create a task.
Signed-off-by: Olivier Gayot <olivier.gayot@canonical.com>
The behavior of asyncio.get_event_loop() will change in a future Python
version. It is deprecated starting Python 3.10.
The functions that we can use instead are:
* asyncio.new_event_loop() - which creates a new event loop
* asyncio.get_running_loop() - which returns the event loop only if it
is already running
Signed-off-by: Olivier Gayot <olivier.gayot@canonical.com>
We now have the view display the user-code fetched via u-a-c and
automatically validate the contract token when the contract selection
succeeds.
If the magic token expires (i.e., u-a-c times out), a new contract
selection is initiated.
Signed-off-by: Olivier Gayot <olivier.gayot@canonical.com>
Tests that use run_coro are at risk of being broken by the introduction
of another test using IsolatedAsyncioTestCase. Switch over to only use
IsolatedAsyncioTestCase.