Add a cleanup command and DBus API
We sometimes talk about using `ostree admin undeploy`, but that doesn't know about the pkgcache, and hence space there leaks until the next rpm-ostree operation. Just for this, we need to expose a cleanup command (and API). But we also need to support cleaning: - repomd - downloads (repo/tmp) So let's start implementing that. Closes: #614 Approved by: jlebon
This commit is contained in:
parent
3c77b6e0a9
commit
a66d27230d
@ -27,6 +27,7 @@ rpm_ostree_SOURCES = src/app/main.c \
|
||||
src/app/rpmostree-builtin-rollback.c \
|
||||
src/app/rpmostree-builtin-deploy.c \
|
||||
src/app/rpmostree-builtin-rebase.c \
|
||||
src/app/rpmostree-builtin-cleanup.c \
|
||||
src/app/rpmostree-builtin-initramfs.c \
|
||||
src/app/rpmostree-pkg-builtins.c \
|
||||
src/app/rpmostree-builtin-status.c \
|
||||
|
@ -334,6 +334,35 @@ Boston, MA 02111-1307, USA.
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><command>cleanup</command></term>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
Commands such as <command>upgrade</command> create new deployments,
|
||||
which affect the next boot, and take up additional storage space. In
|
||||
some cases, you may want to undo and clean up these operations. This
|
||||
command supports both removing additional deployments such as the
|
||||
"pending" deployment (the next boot) as well as the default rollback
|
||||
deployment. Use <option>-p/--pending</option> to remove the pending
|
||||
deployment, and <option>-r/--rollback</option> to remove the
|
||||
rollback.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
The <option>-b/--base</option> option does not affect finished
|
||||
deployments, but will clean up any transient allocated space that
|
||||
may result from interrupted operations. If you want to free up disk
|
||||
space safely, use this option first.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
The <option>-m/--repomd</option> option cleans up cached RPM
|
||||
repodata and any partially downloaded (but not imported) packages.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><command>initramfs</command></term>
|
||||
|
||||
|
@ -37,6 +37,7 @@ static RpmOstreeCommand supported_commands[] = {
|
||||
#ifdef HAVE_COMPOSE_TOOLING
|
||||
{ "compose", rpmostree_builtin_compose },
|
||||
#endif
|
||||
{ "cleanup", rpmostree_builtin_cleanup },
|
||||
{ "db", rpmostree_builtin_db },
|
||||
{ "deploy", rpmostree_builtin_deploy },
|
||||
{ "rebase", rpmostree_builtin_rebase },
|
||||
|
113
src/app/rpmostree-builtin-cleanup.c
Normal file
113
src/app/rpmostree-builtin-cleanup.c
Normal file
@ -0,0 +1,113 @@
|
||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
|
||||
*
|
||||
* Copyright (C) 2017 Colin Walters <walters@verbum.org>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published
|
||||
* by the Free Software Foundation; either version 2 of the licence or (at
|
||||
* your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General
|
||||
* Public License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <glib-unix.h>
|
||||
|
||||
#include "rpmostree-builtins.h"
|
||||
#include "rpmostree-util.h"
|
||||
#include "rpmostree-libbuiltin.h"
|
||||
#include "rpmostree-dbus-helpers.h"
|
||||
|
||||
#include <libglnx.h>
|
||||
|
||||
static char *opt_osname;
|
||||
static gboolean opt_base;
|
||||
static gboolean opt_pending;
|
||||
static gboolean opt_rollback;
|
||||
static gboolean opt_repomd;
|
||||
|
||||
static GOptionEntry option_entries[] = {
|
||||
{ "os", 0, 0, G_OPTION_ARG_STRING, &opt_osname, "Operate on provided OSNAME", "OSNAME" },
|
||||
{ "base", 'b', 0, G_OPTION_ARG_NONE, &opt_base, "Clear temporary files; will leave deployments unchanged", NULL },
|
||||
{ "pending", 'p', 0, G_OPTION_ARG_NONE, &opt_pending, "Remove pending deployment", NULL },
|
||||
{ "rollback", 'r', 0, G_OPTION_ARG_NONE, &opt_rollback, "Remove rollback deployment", NULL },
|
||||
{ "repomd", 'm', 0, G_OPTION_ARG_NONE, &opt_repomd, "Delete cached rpm repo metadata", NULL },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
int
|
||||
rpmostree_builtin_cleanup (int argc,
|
||||
char **argv,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
int exit_status = EXIT_FAILURE;
|
||||
g_autoptr(GOptionContext) context = g_option_context_new ("- Clear cached/pending data");
|
||||
g_autoptr(GPtrArray) cleanup_types = g_ptr_array_new ();
|
||||
glnx_unref_object RPMOSTreeOS *os_proxy = NULL;
|
||||
glnx_unref_object RPMOSTreeSysroot *sysroot_proxy = NULL;
|
||||
g_autofree char *transaction_address = NULL;
|
||||
|
||||
if (!rpmostree_option_context_parse (context,
|
||||
option_entries,
|
||||
&argc, &argv,
|
||||
RPM_OSTREE_BUILTIN_FLAG_REQUIRES_ROOT,
|
||||
cancellable,
|
||||
&sysroot_proxy,
|
||||
error))
|
||||
goto out;
|
||||
|
||||
if (argc < 1 || argc > 2)
|
||||
{
|
||||
rpmostree_usage_error (context, "Too few or too many arguments", error);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (opt_base)
|
||||
g_ptr_array_add (cleanup_types, "base");
|
||||
if (opt_pending)
|
||||
g_ptr_array_add (cleanup_types, "pending-deploy");
|
||||
if (opt_rollback)
|
||||
g_ptr_array_add (cleanup_types, "rollback-deploy");
|
||||
if (opt_repomd)
|
||||
g_ptr_array_add (cleanup_types, "repomd");
|
||||
if (cleanup_types->len == 0)
|
||||
{
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "At least one cleanup option must be specified");
|
||||
goto out;
|
||||
}
|
||||
g_ptr_array_add (cleanup_types, NULL);
|
||||
|
||||
if (!rpmostree_load_os_proxy (sysroot_proxy, opt_osname,
|
||||
cancellable, &os_proxy, error))
|
||||
goto out;
|
||||
|
||||
if (!rpmostree_os_call_cleanup_sync (os_proxy,
|
||||
(const char *const*)cleanup_types->pdata,
|
||||
&transaction_address,
|
||||
cancellable,
|
||||
error))
|
||||
goto out;
|
||||
|
||||
if (!rpmostree_transaction_get_response_sync (sysroot_proxy,
|
||||
transaction_address,
|
||||
cancellable,
|
||||
error))
|
||||
goto out;
|
||||
|
||||
exit_status = EXIT_SUCCESS;
|
||||
out:
|
||||
/* Does nothing if using the message bus. */
|
||||
rpmostree_cleanup_peer ();
|
||||
return exit_status;
|
||||
}
|
@ -46,6 +46,7 @@ BUILTINPROTO(compose);
|
||||
BUILTINPROTO(upgrade);
|
||||
BUILTINPROTO(deploy);
|
||||
BUILTINPROTO(rebase);
|
||||
BUILTINPROTO(cleanup);
|
||||
BUILTINPROTO(rollback);
|
||||
BUILTINPROTO(initramfs);
|
||||
BUILTINPROTO(status);
|
||||
|
@ -188,6 +188,11 @@
|
||||
<arg type="s" name="transaction_address" direction="out"/>
|
||||
</method>
|
||||
|
||||
<method name="Cleanup">
|
||||
<arg type="as" name="elements" direction="in"/>
|
||||
<arg type="s" name="transaction_address" direction="out"/>
|
||||
</method>
|
||||
|
||||
</interface>
|
||||
|
||||
<interface name="org.projectatomic.rpmostree1.Transaction">
|
||||
|
@ -1162,7 +1162,7 @@ overlay_packages (RpmOstreeSysrootUpgrader *self,
|
||||
* deployment, to ensure that upgrades work.
|
||||
*/
|
||||
static gboolean
|
||||
get_base_commit_for_deployment (RpmOstreeSysrootUpgrader *self,
|
||||
get_base_commit_for_deployment (OstreeRepo *repo,
|
||||
OstreeDeployment *deployment,
|
||||
char **out_base,
|
||||
GError **error)
|
||||
@ -1178,7 +1178,7 @@ get_base_commit_for_deployment (RpmOstreeSysrootUpgrader *self,
|
||||
const char *csum = ostree_deployment_get_csum (deployment);
|
||||
g_autofree char *base_rev = NULL;
|
||||
|
||||
if (!commit_get_parent_csum (self->repo, csum, &base_rev, error))
|
||||
if (!commit_get_parent_csum (repo, csum, &base_rev, error))
|
||||
return FALSE;
|
||||
g_assert (base_rev);
|
||||
|
||||
@ -1197,7 +1197,8 @@ get_base_commit_for_deployment (RpmOstreeSysrootUpgrader *self,
|
||||
* can always just re-pull it, but let's try to be nice).
|
||||
**/
|
||||
static gboolean
|
||||
generate_baselayer_refs (RpmOstreeSysrootUpgrader *self,
|
||||
generate_baselayer_refs (OstreeSysroot *sysroot,
|
||||
OstreeRepo *repo,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
@ -1206,12 +1207,12 @@ generate_baselayer_refs (RpmOstreeSysrootUpgrader *self,
|
||||
g_autoptr(GHashTable) bases =
|
||||
g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
|
||||
|
||||
if (!ostree_repo_list_refs_ext (self->repo, "rpmostree/base", &refs,
|
||||
if (!ostree_repo_list_refs_ext (repo, "rpmostree/base", &refs,
|
||||
OSTREE_REPO_LIST_REFS_EXT_NONE,
|
||||
cancellable, error))
|
||||
goto out;
|
||||
|
||||
if (!ostree_repo_prepare_transaction (self->repo, NULL, cancellable, error))
|
||||
if (!ostree_repo_prepare_transaction (repo, NULL, cancellable, error))
|
||||
goto out;
|
||||
|
||||
/* delete all the refs */
|
||||
@ -1223,7 +1224,7 @@ generate_baselayer_refs (RpmOstreeSysrootUpgrader *self,
|
||||
while (g_hash_table_iter_next (&it, &key, NULL))
|
||||
{
|
||||
const char *ref = key;
|
||||
ostree_repo_transaction_set_refspec (self->repo, ref, NULL);
|
||||
ostree_repo_transaction_set_refspec (repo, ref, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1231,7 +1232,7 @@ generate_baselayer_refs (RpmOstreeSysrootUpgrader *self,
|
||||
{
|
||||
guint i = 0;
|
||||
g_autoptr(GPtrArray) deployments =
|
||||
ostree_sysroot_get_deployments (self->sysroot);
|
||||
ostree_sysroot_get_deployments (sysroot);
|
||||
|
||||
/* existing deployments */
|
||||
for (; i < deployments->len; i++)
|
||||
@ -1239,7 +1240,7 @@ generate_baselayer_refs (RpmOstreeSysrootUpgrader *self,
|
||||
OstreeDeployment *deployment = deployments->pdata[i];
|
||||
g_autofree char *base_rev = NULL;
|
||||
|
||||
if (!get_base_commit_for_deployment (self, deployment,
|
||||
if (!get_base_commit_for_deployment (repo, deployment,
|
||||
&base_rev, error))
|
||||
goto out;
|
||||
if (base_rev)
|
||||
@ -1258,16 +1259,16 @@ generate_baselayer_refs (RpmOstreeSysrootUpgrader *self,
|
||||
{
|
||||
const char *base = key;
|
||||
g_autofree char *ref = g_strdup_printf ("rpmostree/base/%u", i++);
|
||||
ostree_repo_transaction_set_refspec (self->repo, ref, base);
|
||||
ostree_repo_transaction_set_refspec (repo, ref, base);
|
||||
}
|
||||
}
|
||||
|
||||
if (!ostree_repo_commit_transaction (self->repo, NULL, cancellable, error))
|
||||
if (!ostree_repo_commit_transaction (repo, NULL, cancellable, error))
|
||||
goto out;
|
||||
|
||||
ret = TRUE;
|
||||
out:
|
||||
ostree_repo_abort_transaction (self->repo, cancellable, NULL);
|
||||
ostree_repo_abort_transaction (repo, cancellable, NULL);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -1308,13 +1309,14 @@ add_package_refs_to_set (RpmOstreeRefSack *rsack,
|
||||
* that set.
|
||||
*/
|
||||
static gboolean
|
||||
clean_pkgcache_orphans (RpmOstreeSysrootUpgrader *self,
|
||||
clean_pkgcache_orphans (OstreeSysroot *sysroot,
|
||||
OstreeRepo *repo,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
glnx_unref_object OstreeRepo *pkgcache_repo = NULL;
|
||||
g_autoptr(GPtrArray) deployments =
|
||||
ostree_sysroot_get_deployments (self->sysroot);
|
||||
ostree_sysroot_get_deployments (sysroot);
|
||||
g_autoptr(GHashTable) current_refs = NULL;
|
||||
g_autoptr(GHashTable) referenced_pkgs = /* cache refs of packages we want to keep */
|
||||
g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
|
||||
@ -1325,7 +1327,7 @@ clean_pkgcache_orphans (RpmOstreeSysrootUpgrader *self,
|
||||
guint64 freed_space;
|
||||
guint n_freed = 0;
|
||||
|
||||
if (!get_pkgcache_repo (self->repo, &pkgcache_repo, cancellable, error))
|
||||
if (!get_pkgcache_repo (repo, &pkgcache_repo, cancellable, error))
|
||||
return FALSE;
|
||||
|
||||
for (guint i = 0; i < deployments->len; i++)
|
||||
@ -1342,12 +1344,12 @@ clean_pkgcache_orphans (RpmOstreeSysrootUpgrader *self,
|
||||
g_autoptr(RpmOstreeRefSack) rsack = NULL;
|
||||
g_autofree char *deployment_dirpath = NULL;
|
||||
|
||||
deployment_dirpath = ostree_sysroot_get_deployment_dirpath (self->sysroot, deployment);
|
||||
deployment_dirpath = ostree_sysroot_get_deployment_dirpath (sysroot, deployment);
|
||||
|
||||
/* We could do this via the commit object, but it's faster
|
||||
* to reuse the existing rpmdb checkout.
|
||||
*/
|
||||
rsack = rpmostree_get_refsack_for_root (ostree_sysroot_get_fd (self->sysroot),
|
||||
rsack = rpmostree_get_refsack_for_root (ostree_sysroot_get_fd (sysroot),
|
||||
deployment_dirpath,
|
||||
cancellable, error);
|
||||
if (rsack == NULL)
|
||||
@ -1392,26 +1394,38 @@ clean_pkgcache_orphans (RpmOstreeSysrootUpgrader *self,
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
sysroot_upgrader_cleanup (RpmOstreeSysrootUpgrader *self,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
/* Clean up to match the current deployments. This used to be a private static,
|
||||
* but is now used by the cleanup txn.
|
||||
*/
|
||||
gboolean
|
||||
rpmostree_sysroot_upgrader_cleanup (OstreeSysroot *sysroot,
|
||||
OstreeRepo *repo,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
int repo_dfd = ostree_repo_get_dfd (repo); /* borrowed */
|
||||
|
||||
/* regenerate the baselayer refs in case we just kicked out an ancient layered
|
||||
* deployment whose base layer is not needed anymore */
|
||||
if (!generate_baselayer_refs (self, cancellable, error))
|
||||
if (!generate_baselayer_refs (sysroot, repo, cancellable, error))
|
||||
return FALSE;
|
||||
|
||||
/* Delete our temporary ref */
|
||||
if (!ostree_repo_set_ref_immediate (self->repo, NULL, RPMOSTREE_TMP_BASE_REF,
|
||||
if (!ostree_repo_set_ref_immediate (repo, NULL, RPMOSTREE_TMP_BASE_REF,
|
||||
NULL, cancellable, error))
|
||||
return FALSE;
|
||||
|
||||
/* and shake it loose */
|
||||
if (!ostree_sysroot_cleanup (self->sysroot, cancellable, error))
|
||||
if (!ostree_sysroot_cleanup (sysroot, cancellable, error))
|
||||
return FALSE;
|
||||
|
||||
if (!clean_pkgcache_orphans (self, cancellable, error))
|
||||
if (!clean_pkgcache_orphans (sysroot, repo, cancellable, error))
|
||||
return FALSE;
|
||||
|
||||
/* delete our checkout dir in case a previous run didn't finish
|
||||
successfully */
|
||||
if (!glnx_shutil_rm_rf_at (repo_dfd, RPMOSTREE_TMP_ROOTFS_DIR,
|
||||
cancellable, error))
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
@ -1483,7 +1497,7 @@ rpmostree_sysroot_upgrader_deploy (RpmOstreeSysrootUpgrader *self,
|
||||
cancellable, error))
|
||||
goto out;
|
||||
|
||||
if (!sysroot_upgrader_cleanup (self, cancellable, error))
|
||||
if (!rpmostree_sysroot_upgrader_cleanup (self->sysroot, self->repo, cancellable, error))
|
||||
goto out;
|
||||
|
||||
ret = TRUE;
|
||||
|
@ -106,4 +106,11 @@ rpmostree_sysroot_upgrader_deploy (RpmOstreeSysrootUpgrader *self,
|
||||
GCancellable *cancellable,
|
||||
GError **error);
|
||||
|
||||
gboolean
|
||||
rpmostree_sysroot_upgrader_cleanup (OstreeSysroot *sysroot,
|
||||
OstreeRepo *repo,
|
||||
GCancellable *cancellable,
|
||||
GError **error);
|
||||
|
||||
|
||||
G_END_DECLS
|
||||
|
@ -806,6 +806,78 @@ out:
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
os_handle_cleanup (RPMOSTreeOS *interface,
|
||||
GDBusMethodInvocation *invocation,
|
||||
const char *const*args)
|
||||
{
|
||||
RpmostreedOS *self = RPMOSTREED_OS (interface);
|
||||
glnx_unref_object RpmostreedTransaction *transaction = NULL;
|
||||
glnx_unref_object OstreeSysroot *ot_sysroot = NULL;
|
||||
g_autoptr(GCancellable) cancellable = g_cancellable_new ();
|
||||
RpmOstreeTransactionCleanupFlags flags = 0;
|
||||
const char *osname;
|
||||
GError *local_error = NULL;
|
||||
|
||||
transaction = merge_compatible_txn (self, invocation);
|
||||
if (transaction)
|
||||
goto out;
|
||||
|
||||
if (!rpmostreed_sysroot_load_state (rpmostreed_sysroot_get (),
|
||||
cancellable,
|
||||
&ot_sysroot,
|
||||
NULL,
|
||||
&local_error))
|
||||
goto out;
|
||||
|
||||
osname = rpmostree_os_get_name (interface);
|
||||
|
||||
for (char **iter = (char**) args; iter && *iter; iter++)
|
||||
{
|
||||
const char *v = *iter;
|
||||
if (strcmp (v, "base") == 0)
|
||||
flags |= RPMOSTREE_TRANSACTION_CLEANUP_BASE;
|
||||
else if (strcmp (v, "pending-deploy") == 0)
|
||||
flags |= RPMOSTREE_TRANSACTION_CLEANUP_PENDING_DEPLOY;
|
||||
else if (strcmp (v, "rollback-deploy") == 0)
|
||||
flags |= RPMOSTREE_TRANSACTION_CLEANUP_ROLLBACK_DEPLOY;
|
||||
else if (strcmp (v, "repomd") == 0)
|
||||
flags |= RPMOSTREE_TRANSACTION_CLEANUP_REPOMD;
|
||||
else
|
||||
{
|
||||
g_set_error (&local_error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||
"Invalid cleanup type: %s", v);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
transaction = rpmostreed_transaction_new_cleanup (invocation,
|
||||
ot_sysroot,
|
||||
osname,
|
||||
flags,
|
||||
cancellable,
|
||||
&local_error);
|
||||
if (transaction == NULL)
|
||||
goto out;
|
||||
|
||||
rpmostreed_transaction_monitor_add (self->transaction_monitor, transaction);
|
||||
|
||||
out:
|
||||
if (local_error != NULL)
|
||||
{
|
||||
g_dbus_method_invocation_take_error (invocation, local_error);
|
||||
}
|
||||
else
|
||||
{
|
||||
const char *client_address;
|
||||
client_address = rpmostreed_transaction_get_client_address (transaction);
|
||||
rpmostree_os_complete_pkg_change (interface, invocation, client_address);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
os_handle_get_cached_rebase_rpm_diff (RPMOSTreeOS *interface,
|
||||
GDBusMethodInvocation *invocation,
|
||||
@ -1191,6 +1263,7 @@ rpmostreed_os_iface_init (RPMOSTreeOSIface *iface)
|
||||
iface->handle_rebase = os_handle_rebase;
|
||||
iface->handle_pkg_change = os_handle_pkg_change;
|
||||
iface->handle_set_initramfs_state = os_handle_set_initramfs_state;
|
||||
iface->handle_cleanup = os_handle_cleanup;
|
||||
iface->handle_get_cached_rebase_rpm_diff = os_handle_get_cached_rebase_rpm_diff;
|
||||
iface->handle_download_rebase_rpm_diff = os_handle_download_rebase_rpm_diff;
|
||||
iface->handle_get_cached_deploy_rpm_diff = os_handle_get_cached_deploy_rpm_diff;
|
||||
|
@ -27,6 +27,7 @@
|
||||
#include "rpmostreed-sysroot.h"
|
||||
#include "rpmostree-sysroot-upgrader.h"
|
||||
#include "rpmostree-util.h"
|
||||
#include "rpmostree-core.h"
|
||||
#include "rpmostreed-utils.h"
|
||||
|
||||
static gboolean
|
||||
@ -954,3 +955,213 @@ rpmostreed_transaction_new_initramfs_state (GDBusMethodInvocation *invocation,
|
||||
|
||||
return (RpmostreedTransaction *) self;
|
||||
}
|
||||
|
||||
/* ================================ Cleanup ================================ */
|
||||
|
||||
typedef struct {
|
||||
RpmostreedTransaction parent;
|
||||
char *osname;
|
||||
RpmOstreeTransactionCleanupFlags flags;
|
||||
} CleanupTransaction;
|
||||
|
||||
typedef RpmostreedTransactionClass CleanupTransactionClass;
|
||||
|
||||
GType cleanup_transaction_get_type (void);
|
||||
|
||||
G_DEFINE_TYPE (CleanupTransaction,
|
||||
cleanup_transaction,
|
||||
RPMOSTREED_TYPE_TRANSACTION)
|
||||
|
||||
static void
|
||||
cleanup_transaction_finalize (GObject *object)
|
||||
{
|
||||
CleanupTransaction *self;
|
||||
|
||||
self = (CleanupTransaction *) object;
|
||||
g_free (self->osname);
|
||||
|
||||
G_OBJECT_CLASS (cleanup_transaction_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
remove_directory_content_if_exists (int dfd,
|
||||
const char *path,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
glnx_fd_close int fd = -1;
|
||||
g_auto(GLnxDirFdIterator) dfd_iter = { 0, };
|
||||
|
||||
fd = glnx_opendirat_with_errno (dfd, path, TRUE);
|
||||
if (fd < 0)
|
||||
{
|
||||
if (errno != ENOENT)
|
||||
{
|
||||
glnx_set_error_from_errno (error);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!glnx_dirfd_iterator_init_take_fd (fd, &dfd_iter, error))
|
||||
return FALSE;
|
||||
fd = -1;
|
||||
|
||||
while (TRUE)
|
||||
{
|
||||
struct dirent *dent = NULL;
|
||||
|
||||
if (!glnx_dirfd_iterator_next_dent (&dfd_iter, &dent, cancellable, error))
|
||||
return FALSE;
|
||||
if (dent == NULL)
|
||||
break;
|
||||
|
||||
if (!glnx_shutil_rm_rf_at (dfd_iter.fd, dent->d_name, cancellable, error))
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* This is a bit like ostree_sysroot_simple_write_deployment() */
|
||||
static GPtrArray *
|
||||
get_filtered_deployments (OstreeSysroot *sysroot,
|
||||
const char *osname,
|
||||
gboolean cleanup_pending,
|
||||
gboolean cleanup_rollback)
|
||||
{
|
||||
g_autoptr(GPtrArray) deployments = ostree_sysroot_get_deployments (sysroot);
|
||||
g_autoptr(GPtrArray) new_deployments = g_ptr_array_new_with_free_func (g_object_unref);
|
||||
OstreeDeployment *booted_deployment = NULL;
|
||||
gboolean found_booted = FALSE;
|
||||
|
||||
booted_deployment = ostree_sysroot_get_booted_deployment (sysroot);
|
||||
|
||||
for (guint i = 0; i < deployments->len; i++)
|
||||
{
|
||||
OstreeDeployment *deployment = deployments->pdata[i];
|
||||
|
||||
/* Is this deployment booted? If so, note we're past the booted,
|
||||
* and ensure it's added. */
|
||||
if (booted_deployment != NULL &&
|
||||
ostree_deployment_equal (deployment, booted_deployment))
|
||||
{
|
||||
found_booted = TRUE;
|
||||
g_ptr_array_add (new_deployments, g_object_ref (deployment));
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Is this deployment for a different osname? Keep it. */
|
||||
if (strcmp (ostree_deployment_get_osname (deployment), osname) != 0)
|
||||
{
|
||||
g_ptr_array_add (new_deployments, g_object_ref (deployment));
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Now, we may skip this deployment, i.e. GC it. */
|
||||
if (!found_booted && cleanup_pending)
|
||||
continue;
|
||||
|
||||
if (found_booted && cleanup_rollback)
|
||||
continue;
|
||||
|
||||
/* Otherwise, add it */
|
||||
g_ptr_array_add (new_deployments, g_object_ref (deployment));
|
||||
}
|
||||
|
||||
if (new_deployments->len == deployments->len)
|
||||
return NULL;
|
||||
return g_steal_pointer (&new_deployments);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
cleanup_transaction_execute (RpmostreedTransaction *transaction,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
CleanupTransaction *self = (CleanupTransaction *) transaction;
|
||||
OstreeSysroot *sysroot;
|
||||
glnx_unref_object OstreeRepo *repo = NULL;
|
||||
const gboolean cleanup_pending = (self->flags & RPMOSTREE_TRANSACTION_CLEANUP_PENDING_DEPLOY) > 0;
|
||||
const gboolean cleanup_rollback = (self->flags & RPMOSTREE_TRANSACTION_CLEANUP_ROLLBACK_DEPLOY) > 0;
|
||||
|
||||
sysroot = rpmostreed_transaction_get_sysroot (transaction);
|
||||
if (!ostree_sysroot_get_repo (sysroot, &repo, cancellable, error))
|
||||
return FALSE;
|
||||
|
||||
if (cleanup_pending || cleanup_rollback)
|
||||
{
|
||||
g_autoptr(GPtrArray) new_deployments = get_filtered_deployments (sysroot, self->osname,
|
||||
cleanup_pending,
|
||||
cleanup_rollback);
|
||||
if (new_deployments)
|
||||
{
|
||||
/* TODO - expose the skip cleanup flag in libostree, use it here */
|
||||
if (!ostree_sysroot_write_deployments (sysroot, new_deployments, cancellable, error))
|
||||
return FALSE;
|
||||
/* And ensure we fall through to base cleanup */
|
||||
self->flags |= RPMOSTREE_TRANSACTION_CLEANUP_BASE;
|
||||
}
|
||||
else
|
||||
{
|
||||
g_print ("Deployments unchanged.\n");
|
||||
}
|
||||
}
|
||||
if (self->flags & RPMOSTREE_TRANSACTION_CLEANUP_BASE)
|
||||
{
|
||||
if (!rpmostree_sysroot_upgrader_cleanup (sysroot, repo, cancellable, error))
|
||||
return FALSE;
|
||||
}
|
||||
if (self->flags & RPMOSTREE_TRANSACTION_CLEANUP_REPOMD)
|
||||
{
|
||||
if (!remove_directory_content_if_exists (AT_FDCWD, RPMOSTREE_CORE_CACHEDIR, cancellable, error))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
cleanup_transaction_class_init (CleanupTransactionClass *class)
|
||||
{
|
||||
GObjectClass *object_class;
|
||||
|
||||
object_class = G_OBJECT_CLASS (class);
|
||||
object_class->finalize = cleanup_transaction_finalize;
|
||||
|
||||
class->execute = cleanup_transaction_execute;
|
||||
}
|
||||
|
||||
static void
|
||||
cleanup_transaction_init (CleanupTransaction *self)
|
||||
{
|
||||
}
|
||||
|
||||
RpmostreedTransaction *
|
||||
rpmostreed_transaction_new_cleanup (GDBusMethodInvocation *invocation,
|
||||
OstreeSysroot *sysroot,
|
||||
const char *osname,
|
||||
RpmOstreeTransactionCleanupFlags flags,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
CleanupTransaction *self;
|
||||
|
||||
g_return_val_if_fail (G_IS_DBUS_METHOD_INVOCATION (invocation), NULL);
|
||||
g_return_val_if_fail (OSTREE_IS_SYSROOT (sysroot), NULL);
|
||||
|
||||
self = g_initable_new (cleanup_transaction_get_type (),
|
||||
cancellable, error,
|
||||
"invocation", invocation,
|
||||
"sysroot-path", gs_file_get_path_cached (ostree_sysroot_get_path (sysroot)),
|
||||
NULL);
|
||||
|
||||
if (self != NULL)
|
||||
{
|
||||
self->osname = g_strdup (osname);
|
||||
self->flags = flags;
|
||||
}
|
||||
|
||||
return (RpmostreedTransaction *) self;
|
||||
|
||||
}
|
||||
|
@ -76,3 +76,18 @@ rpmostreed_transaction_new_initramfs_state (GDBusMethodInvocation *invocat
|
||||
gboolean reboot,
|
||||
GCancellable *cancellable,
|
||||
GError **error);
|
||||
|
||||
typedef enum {
|
||||
RPMOSTREE_TRANSACTION_CLEANUP_BASE = (1 << 0),
|
||||
RPMOSTREE_TRANSACTION_CLEANUP_PENDING_DEPLOY = (1 << 1),
|
||||
RPMOSTREE_TRANSACTION_CLEANUP_ROLLBACK_DEPLOY = (1 << 2),
|
||||
RPMOSTREE_TRANSACTION_CLEANUP_REPOMD = (1 << 3),
|
||||
} RpmOstreeTransactionCleanupFlags;
|
||||
|
||||
RpmostreedTransaction *
|
||||
rpmostreed_transaction_new_cleanup (GDBusMethodInvocation *invocation,
|
||||
OstreeSysroot *sysroot,
|
||||
const char *osname,
|
||||
RpmOstreeTransactionCleanupFlags flags,
|
||||
GCancellable *cancellable,
|
||||
GError **error);
|
||||
|
@ -340,8 +340,8 @@ rpmostree_context_new_system (GCancellable *cancellable,
|
||||
* override this for testing. */
|
||||
if (g_getenv("RPMOSTREE_USE_CACHED_METADATA") == NULL)
|
||||
dnf_context_set_cache_age (self->hifctx, 0);
|
||||
dnf_context_set_cache_dir (self->hifctx, "/var/cache/rpm-ostree/" RPMOSTREE_DIR_CACHE_REPOMD);
|
||||
dnf_context_set_solv_dir (self->hifctx, "/var/cache/rpm-ostree/" RPMOSTREE_DIR_CACHE_SOLV);
|
||||
dnf_context_set_cache_dir (self->hifctx, RPMOSTREE_CORE_CACHEDIR RPMOSTREE_DIR_CACHE_REPOMD);
|
||||
dnf_context_set_solv_dir (self->hifctx, RPMOSTREE_CORE_CACHEDIR RPMOSTREE_DIR_CACHE_SOLV);
|
||||
dnf_context_set_lock_dir (self->hifctx, "/run/rpm-ostree/" RPMOSTREE_DIR_LOCK);
|
||||
dnf_context_set_user_agent (self->hifctx, PACKAGE_NAME "/" PACKAGE_VERSION);
|
||||
|
||||
|
@ -26,6 +26,8 @@
|
||||
|
||||
#include "libglnx.h"
|
||||
|
||||
#define RPMOSTREE_CORE_CACHEDIR "/var/cache/rpm-ostree/"
|
||||
|
||||
#define RPMOSTREE_TYPE_CONTEXT (rpmostree_context_get_type ())
|
||||
G_DECLARE_FINAL_TYPE (RpmOstreeContext, rpmostree_context, RPMOSTREE, CONTEXT, GObject)
|
||||
|
||||
|
@ -77,3 +77,16 @@ vm_reboot
|
||||
|
||||
vm_assert_layered_pkg foo absent
|
||||
echo "ok pkg foo removed"
|
||||
|
||||
vm_rpmostree cleanup -b
|
||||
vm_assert_status_jq '.deployments|length == 2'
|
||||
echo "ok baseline cleanup"
|
||||
vm_rpmostree cleanup -r
|
||||
vm_assert_status_jq '.deployments|length == 1'
|
||||
vm_rpmostree cleanup -pr
|
||||
vm_assert_status_jq '.deployments|length == 1'
|
||||
vm_rpmostree pkg-add foo-1.0
|
||||
vm_assert_status_jq '.deployments|length == 2'
|
||||
vm_rpmostree cleanup -pr
|
||||
vm_assert_status_jq '.deployments|length == 1'
|
||||
echo "ok cleanup"
|
||||
|
Loading…
Reference in New Issue
Block a user