Add "status" command
Add status command to display information the current deployment of the OSTree repository when OSTree is deployed. This command will not work from a non-OSTree deployed system. The status command will display the current running branch, in green. The current commit that is deployed and the Debian version has been deployed. Also update tox.ini and bindep.txt to support ostree. Test Plan PASSED Installed apt-ostree from git repo. PASSED Run sudo apt-ostree compose create \ --base config/debian/bookworm \ --repo /repo debian/bookworm PASSED Run "apt-ostree compose image --base config/debian/image \ --repo=/repo test" PASSED Start VM. PASSED Run the apt-ostree status command. Story: 2010867 Task: 48556 Change-Id: Ie55007e83869f5c491f97c1828508e7c8085f47a Signed-off-by: Charles Short <charles.short@windriver.com>
This commit is contained in:
parent
3ef2dde60f
commit
03f0c8267f
@ -11,6 +11,8 @@ class State:
|
||||
def __init__(self):
|
||||
self.debug = False
|
||||
self.workspace = None
|
||||
self.repo = None
|
||||
self.branch = None
|
||||
|
||||
|
||||
# pass state between command and apt-ostree sub-commands
|
||||
|
@ -14,6 +14,7 @@ from apt_ostree.cmd.options import debug_option
|
||||
from apt_ostree.cmd.options import workspace_option
|
||||
from apt_ostree.cmd import pass_state_context
|
||||
from apt_ostree.cmd.repo import repo
|
||||
from apt_ostree.cmd.status import status
|
||||
from apt_ostree.cmd.version import version
|
||||
from apt_ostree.log import setup_log
|
||||
|
||||
@ -41,4 +42,5 @@ def main():
|
||||
|
||||
cli.add_command(compose)
|
||||
cli.add_command(repo)
|
||||
cli.add_command(status)
|
||||
cli.add_command(version)
|
||||
|
29
apt_ostree/cmd/status.py
Normal file
29
apt_ostree/cmd/status.py
Normal file
@ -0,0 +1,29 @@
|
||||
"""
|
||||
Copyright (c) 2023 Wind River Systems, Inc.
|
||||
|
||||
SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
"""
|
||||
|
||||
import errno
|
||||
import sys
|
||||
|
||||
import click
|
||||
|
||||
from apt_ostree.cmd import pass_state_context
|
||||
from apt_ostree.status import Status
|
||||
|
||||
|
||||
@click.command(help="Get the status of the booted system.")
|
||||
@pass_state_context
|
||||
def status(state):
|
||||
try:
|
||||
Status(state).get_deployment()
|
||||
except KeyboardInterrupt:
|
||||
click.secho("\n" + ("Exiting at your request."))
|
||||
sys.exit(130)
|
||||
except BrokenPipeError:
|
||||
sys.exit()
|
||||
except OSError as error:
|
||||
if error.errno == errno.ENOSPC:
|
||||
sys.exit("errror - No space left on device.")
|
@ -6,9 +6,17 @@ SPDX-License-Identifier: Apache-2.0
|
||||
"""
|
||||
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
import click
|
||||
|
||||
from apt_ostree.utils import run_command
|
||||
|
||||
# pylint: disable=wrong-import-position
|
||||
import gi
|
||||
gi.require_version("OSTree", "1.0")
|
||||
from gi.repository import Gio, GLib, OSTree # noqa: H301
|
||||
|
||||
|
||||
class Ostree:
|
||||
def __init__(self, state):
|
||||
@ -36,3 +44,48 @@ class Ostree:
|
||||
cmd += [str(root)]
|
||||
r = run_command(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||
return r
|
||||
|
||||
def get_sysroot(self):
|
||||
"""Load the /ostree directory (sysroot)."""
|
||||
sysroot = OSTree.Sysroot()
|
||||
if not sysroot.load():
|
||||
click.secho("Unable to load /sysroot", fg="red")
|
||||
sys.exit(1)
|
||||
return sysroot
|
||||
|
||||
def open_ostree(self):
|
||||
""""Open the ostree repository."""
|
||||
if self.state.repo:
|
||||
repo = OSTree.Repo.new(Gio.File.new_for_path(str(self.state.repo)))
|
||||
if not repo.open(None):
|
||||
click.secho(
|
||||
"Opening the archive OSTree repository failed.", fg="red")
|
||||
sys.exit(1)
|
||||
else:
|
||||
sysroot = self.get_sysroot()
|
||||
_, repo = sysroot.get_repo()
|
||||
if not repo.open():
|
||||
click.secho(
|
||||
"Opening the archive OSTree repository failed.", fg="red")
|
||||
sys.exit(1)
|
||||
return repo
|
||||
|
||||
def get_branch(self):
|
||||
"""Get a branch in a current deployment."""
|
||||
if self.state.branch:
|
||||
return self.state.branch
|
||||
else:
|
||||
sysroot = self.get_sysroot()
|
||||
deployment = sysroot.get_booted_deployment()
|
||||
origin = deployment.get_origin()
|
||||
try:
|
||||
refspec = origin.get_string("origin", "refspec")
|
||||
except GLib.Error as e:
|
||||
# If not a "key not found" error then raise the exception
|
||||
if not e.matches(GLib.KeyFile.error_quark(),
|
||||
GLib.KeyFileError.KEY_NOT_FOUND):
|
||||
raise (e)
|
||||
# Fallback to `baserefspec`
|
||||
refspec = origin.get_string('origin', 'baserefspec')
|
||||
|
||||
return refspec
|
||||
|
72
apt_ostree/status.py
Normal file
72
apt_ostree/status.py
Normal file
@ -0,0 +1,72 @@
|
||||
"""
|
||||
Copyright (c) 2023 Wind River Systems, Inc.
|
||||
|
||||
SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
"""
|
||||
import pathlib
|
||||
import shlex
|
||||
|
||||
from rich.console import Console
|
||||
from rich.table import Table
|
||||
|
||||
from apt_ostree.ostree import Ostree
|
||||
|
||||
|
||||
class Status:
|
||||
def __init__(self, state):
|
||||
self.state = state
|
||||
self.ostree = Ostree(state)
|
||||
self.console = Console()
|
||||
self.sysroot = None
|
||||
|
||||
def get_deployment(self):
|
||||
"""Get information about the current deployment"""
|
||||
self.sysroot = self.ostree.get_sysroot()
|
||||
deployment = self.sysroot.get_booted_deployment()
|
||||
|
||||
table = Table(box=None)
|
||||
table.add_row("Current Deployment:")
|
||||
table.add_row()
|
||||
table.add_row("Branch:", f"[green]{self.ostree.get_branch()}[/green]")
|
||||
table.add_row("Commit:", f"{deployment.get_csum()}")
|
||||
|
||||
root = self._get_deployment_path(deployment)
|
||||
os_release = self._get_os_release(root)
|
||||
if deployment.get_osname() == "debian":
|
||||
release = os_release.get("PRETTY_NAME").replace('"', '')
|
||||
table.add_row("Debian Release:", release)
|
||||
|
||||
table.add_row()
|
||||
|
||||
if table.columns:
|
||||
self.console.print(table)
|
||||
|
||||
def _get_deployment_path(self, target_deployment):
|
||||
"""Get the path for the /sysroot"""
|
||||
return pathlib.Path("/" + self.sysroot.get_deployment_dirpath(
|
||||
target_deployment))
|
||||
|
||||
def _get_os_release(self, rootfs):
|
||||
"""Parse the /etc/os-release file."""
|
||||
try:
|
||||
file = open(rootfs.joinpath("/etc/os-release"), encoding="utf-8")
|
||||
except FileNotFoundError:
|
||||
try:
|
||||
file = open(rootfs.joinpath(
|
||||
"/usr/lib/os-release"), encoding="utf-8")
|
||||
except FileNotFoundError:
|
||||
return {}
|
||||
|
||||
os_release = {}
|
||||
for line in file.readlines():
|
||||
line = line.strip()
|
||||
if not line or line.startswith("#"):
|
||||
continue
|
||||
try:
|
||||
k, v = line.split("=")
|
||||
(v_parsed, ) = shlex.split(v) # expect only one token
|
||||
except ValueError:
|
||||
continue
|
||||
os_release[k] = v
|
||||
return os_release
|
@ -1 +1,7 @@
|
||||
python3-apt [platform:dpkg]
|
||||
ostree [platform:dpkg]
|
||||
libostree-dev [platform:dpkg]
|
||||
gir1.2-glib-2.0 [platform:dpkg]
|
||||
gir1.2-ostree-1.0 [platform:dpkg]
|
||||
libcairo2-dev [platform:dpkg]
|
||||
libgirepository1.0-dev [platform:dpkg]
|
||||
|
11
tox.ini
11
tox.ini
@ -7,8 +7,8 @@ ignore_basepython_conflict = true
|
||||
|
||||
[testenv]
|
||||
basepython = python3
|
||||
usedevelop = false
|
||||
sitepacages = True
|
||||
usedevelop = true
|
||||
sitepacages = False
|
||||
setenv =
|
||||
PYTHONWARNINGS=default::DeprecationWarning
|
||||
OS_STDOUT_CAPTURE=1
|
||||
@ -39,8 +39,6 @@ commands =
|
||||
coverage html -d cover
|
||||
coverage xml -o cover/coverage.xml
|
||||
|
||||
|
||||
|
||||
[testenv:docs]
|
||||
deps = -r{toxinidir}/doc/requirements.txt
|
||||
commands = sphinx-build -W -b html doc/source doc/build/html
|
||||
@ -66,3 +64,8 @@ commands =
|
||||
skip_install = True
|
||||
deps = bindep
|
||||
commands = bindep test
|
||||
|
||||
[stestr]
|
||||
test_path=./apt_ostree/tests
|
||||
top_dir=./
|
||||
group_regex=([^\.]*\.)*
|
||||
|
Loading…
x
Reference in New Issue
Block a user