mirror of
https://github.com/freedomofpress/dangerzone.git
synced 2025-04-28 18:02:38 +02:00
Fix wrong container runtime detection on Linux
Use "podman" when on Linux, and "docker" otherwise. Show what the error was when the command failed.
This commit is contained in:
parent
9b9e265b11
commit
a014fee3e5
3 changed files with 75 additions and 17 deletions
|
@ -5,7 +5,7 @@ import platform
|
||||||
import signal
|
import signal
|
||||||
import sys
|
import sys
|
||||||
import typing
|
import typing
|
||||||
from typing import Dict, List, Optional
|
from typing import List, Optional
|
||||||
|
|
||||||
import click
|
import click
|
||||||
import colorama
|
import colorama
|
||||||
|
|
|
@ -10,14 +10,18 @@ from typing import List, Optional
|
||||||
# FIXME: See https://github.com/freedomofpress/dangerzone/issues/320 for more details.
|
# FIXME: See https://github.com/freedomofpress/dangerzone/issues/320 for more details.
|
||||||
if typing.TYPE_CHECKING:
|
if typing.TYPE_CHECKING:
|
||||||
from PySide2 import QtCore, QtGui, QtSvg, QtWidgets
|
from PySide2 import QtCore, QtGui, QtSvg, QtWidgets
|
||||||
from PySide2.QtWidgets import QAction
|
from PySide2.QtCore import Qt
|
||||||
|
from PySide2.QtWidgets import QAction, QTextEdit
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
from PySide6 import QtCore, QtGui, QtSvg, QtWidgets
|
from PySide6 import QtCore, QtGui, QtSvg, QtWidgets
|
||||||
|
from PySide6.QtCore import Qt
|
||||||
from PySide6.QtGui import QAction
|
from PySide6.QtGui import QAction
|
||||||
|
from PySide6.QtWidgets import QTextEdit
|
||||||
except ImportError:
|
except ImportError:
|
||||||
from PySide2 import QtCore, QtGui, QtSvg, QtWidgets
|
from PySide2 import QtCore, QtGui, QtSvg, QtWidgets
|
||||||
from PySide2.QtWidgets import QAction
|
from PySide2.QtWidgets import QAction, QTextEdit
|
||||||
|
from PySide2.QtCore import Qt
|
||||||
|
|
||||||
from .. import errors
|
from .. import errors
|
||||||
from ..document import SAFE_EXTENSION, Document
|
from ..document import SAFE_EXTENSION, Document
|
||||||
|
@ -434,10 +438,29 @@ class WaitingWidgetContainer(WaitingWidget):
|
||||||
self.buttons = QtWidgets.QWidget()
|
self.buttons = QtWidgets.QWidget()
|
||||||
self.buttons.setLayout(buttons_layout)
|
self.buttons.setLayout(buttons_layout)
|
||||||
|
|
||||||
|
# Error
|
||||||
|
self.error_text = QTextEdit()
|
||||||
|
self.error_text.setReadOnly(True)
|
||||||
|
self.error_text.setStyleSheet(
|
||||||
|
"""
|
||||||
|
QTextEdit {
|
||||||
|
font-family: Consolas, Monospace;
|
||||||
|
font-size: 12px;
|
||||||
|
background-color: #fff;
|
||||||
|
color: #000;
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
self.error_text.setVisible(False)
|
||||||
|
# Enable copying
|
||||||
|
self.error_text.setTextInteractionFlags(Qt.TextSelectableByMouse)
|
||||||
|
|
||||||
# Layout
|
# Layout
|
||||||
layout = QtWidgets.QVBoxLayout()
|
layout = QtWidgets.QVBoxLayout()
|
||||||
layout.addStretch()
|
layout.addStretch()
|
||||||
layout.addWidget(self.label)
|
layout.addWidget(self.label)
|
||||||
|
layout.addWidget(self.error_text)
|
||||||
layout.addStretch()
|
layout.addStretch()
|
||||||
layout.addWidget(self.buttons)
|
layout.addWidget(self.buttons)
|
||||||
layout.addStretch()
|
layout.addStretch()
|
||||||
|
@ -448,49 +471,84 @@ class WaitingWidgetContainer(WaitingWidget):
|
||||||
|
|
||||||
def check_state(self) -> None:
|
def check_state(self) -> None:
|
||||||
state: Optional[str] = None
|
state: Optional[str] = None
|
||||||
|
error: Optional[str] = None
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if isinstance( # Sanity check
|
if isinstance( # Sanity check
|
||||||
self.dangerzone.isolation_provider, Container
|
self.dangerzone.isolation_provider, Container
|
||||||
):
|
):
|
||||||
container_runtime = self.dangerzone.isolation_provider.get_runtime()
|
container_runtime = self.dangerzone.isolation_provider.get_runtime()
|
||||||
|
runtime_name = self.dangerzone.isolation_provider.get_runtime_name()
|
||||||
except NoContainerTechException as e:
|
except NoContainerTechException as e:
|
||||||
log.error(str(e))
|
log.error(str(e))
|
||||||
state = "not_installed"
|
state = "not_installed"
|
||||||
|
|
||||||
else:
|
else:
|
||||||
# Can we run `docker image ls` without an error
|
# Can we run `docker/podman image ls` without an error
|
||||||
with subprocess.Popen(
|
with subprocess.Popen(
|
||||||
[container_runtime, "image", "ls"],
|
[container_runtime, "image", "ls"],
|
||||||
stdout=subprocess.DEVNULL,
|
stdout=subprocess.DEVNULL,
|
||||||
stderr=subprocess.DEVNULL,
|
stderr=subprocess.PIPE,
|
||||||
startupinfo=get_subprocess_startupinfo(),
|
startupinfo=get_subprocess_startupinfo(),
|
||||||
) as p:
|
) as p:
|
||||||
p.communicate()
|
_, stderr = p.communicate()
|
||||||
if p.returncode != 0:
|
if p.returncode != 0:
|
||||||
log.error("Docker is not running")
|
log.error(f"{runtime_name} is not running")
|
||||||
state = "not_running"
|
state = "not_running"
|
||||||
|
error = stderr.decode()
|
||||||
else:
|
else:
|
||||||
# Always try installing the container
|
# Always try installing the container
|
||||||
state = "install_container"
|
state = "install_container"
|
||||||
|
|
||||||
# Update the state
|
# Update the state
|
||||||
self.state_change(state)
|
self.state_change(state, error)
|
||||||
|
|
||||||
def state_change(self, state: str) -> None:
|
def state_change(self, state: str, error: str | None = None) -> None:
|
||||||
if state == "not_installed":
|
if state == "not_installed":
|
||||||
self.label.setText(
|
if platform.system() == "Linux":
|
||||||
"<strong>Dangerzone Requires Docker Desktop</strong><br><br><a href='https://www.docker.com/products/docker-desktop'>Download Docker Desktop</a>, install it, and open it."
|
self.label.setText(
|
||||||
)
|
(
|
||||||
|
"<strong>Dangerzone requires Podman</strong><br><br>"
|
||||||
|
"Install it and retry."
|
||||||
|
)
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
self.label.setText(
|
||||||
|
(
|
||||||
|
"<strong>Dangerzone requires Docker Desktop</strong><br><br>"
|
||||||
|
"<a href='https://www.docker.com/products/docker-desktop'>Download Docker Desktop</a>"
|
||||||
|
", install it, and open it."
|
||||||
|
)
|
||||||
|
)
|
||||||
self.buttons.show()
|
self.buttons.show()
|
||||||
elif state == "not_running":
|
elif state == "not_running":
|
||||||
self.label.setText(
|
if platform.system() == "Linux":
|
||||||
"<strong>Dangerzone Requires Docker Desktop</strong><br><br>Docker is installed but isn't running.<br><br>Open Docker and make sure it's running in the background."
|
# "not_running" here means that the `podman image ls` command failed.
|
||||||
)
|
message = (
|
||||||
|
"<strong>Dangerzone requires Podman</strong><br><br>"
|
||||||
|
"Podman is installed but cannot run properly. See errors below"
|
||||||
|
)
|
||||||
|
if error:
|
||||||
|
self.error_text.setPlainText(error)
|
||||||
|
self.error_text.setVisible(True)
|
||||||
|
|
||||||
|
self.label.setText(message)
|
||||||
|
|
||||||
|
else:
|
||||||
|
self.label.setText(
|
||||||
|
(
|
||||||
|
"<strong>Dangerzone requires Docker Desktop</strong><br><br>"
|
||||||
|
"Docker is installed but isn't running.<br><br>"
|
||||||
|
"Open Docker and make sure it's running in the background."
|
||||||
|
)
|
||||||
|
)
|
||||||
self.buttons.show()
|
self.buttons.show()
|
||||||
else:
|
else:
|
||||||
self.label.setText(
|
self.label.setText(
|
||||||
"Installing the Dangerzone container image.<br><br>This might take a few minutes..."
|
(
|
||||||
|
"Installing the Dangerzone container image.<br><br>"
|
||||||
|
"This might take a few minutes..."
|
||||||
|
)
|
||||||
)
|
)
|
||||||
self.buttons.hide()
|
self.buttons.hide()
|
||||||
self.install_container_t = InstallContainerThread(self.dangerzone)
|
self.install_container_t = InstallContainerThread(self.dangerzone)
|
||||||
|
|
|
@ -242,7 +242,7 @@ class Container(IsolationProvider):
|
||||||
# `int`.
|
# `int`.
|
||||||
#
|
#
|
||||||
# See https://stackoverflow.com/a/37888668
|
# See https://stackoverflow.com/a/37888668
|
||||||
if not type(val) == _type:
|
if type(val) is not _type:
|
||||||
raise ValueError("Status field has incorrect type")
|
raise ValueError("Status field has incorrect type")
|
||||||
|
|
||||||
def parse_progress_trusted(self, document: Document, line: str) -> None:
|
def parse_progress_trusted(self, document: Document, line: str) -> None:
|
||||||
|
|
Loading…
Reference in a new issue