daemon: Check for updated rpms when upgrading
This closes a longstanding bug - since package layering first landed, we only checked for newer RPMs if the base tree changed. In some scenarios like RHELAH, this doesn't matter much by default since they move at the same cadence. Except if you use EPEL for example. In Fedora, today the FAH releases are async of the rpm-md repos, and there's also COPR which can update more than once a day even. We should check for both update sources. Luckily we'd already introduced logic for this in the treecompose case (checksumming the depsolved package sack). We just need to start using it for client side assembly too. Closes: https://github.com/projectatomic/rpm-ostree/issues/391 Closes: #911 Approved by: jlebon
This commit is contained in:
parent
8dddefbad3
commit
b6705f3feb
@ -69,12 +69,15 @@ struct RpmOstreeSysrootUpgrader {
|
||||
RpmOstreeRefSack *rsack;
|
||||
char *metatmpdir_path;
|
||||
int metatmpdir_dfd;
|
||||
|
||||
RpmOstreeContext *ctx;
|
||||
|
||||
GPtrArray *overlay_packages; /* Finalized list of pkgs to overlay */
|
||||
GPtrArray *override_remove_packages; /* Finalized list of base pkgs to remove */
|
||||
GPtrArray *override_replace_local_packages; /* Finalized list of local base pkgs to replace */
|
||||
|
||||
gboolean layering_initialized; /* Whether layering_type is known */
|
||||
RpmOstreeSysrootUpgraderLayeringType layering_type;
|
||||
gboolean layering_changed; /* Whether changes to layering should result in a new commit */
|
||||
char *base_revision; /* Non-layered replicated commit */
|
||||
char *final_revision; /* Computed by layering; if NULL, only using base_revision */
|
||||
};
|
||||
@ -194,7 +197,7 @@ rpmostree_sysroot_upgrader_finalize (GObject *object)
|
||||
RpmOstreeSysrootUpgrader *self = RPMOSTREE_SYSROOT_UPGRADER (object);
|
||||
|
||||
g_clear_pointer (&self->rsack, rpmostree_refsack_unref);
|
||||
|
||||
g_clear_object (&self->ctx);
|
||||
if (self->tmprootfs_dfd != -1)
|
||||
(void)close (self->tmprootfs_dfd);
|
||||
|
||||
@ -368,16 +371,17 @@ rpmostree_sysroot_upgrader_get_merge_deployment (RpmOstreeSysrootUpgrader *self)
|
||||
}
|
||||
|
||||
/*
|
||||
* Like ostree_sysroot_upgrader_pull(), but modified to handle layered packages.
|
||||
* Like ostree_sysroot_upgrader_pull(), but also handles the `baserefspec` we
|
||||
* use when doing layered packages.
|
||||
*/
|
||||
gboolean
|
||||
rpmostree_sysroot_upgrader_pull (RpmOstreeSysrootUpgrader *self,
|
||||
const char *dir_to_pull,
|
||||
OstreeRepoPullFlags flags,
|
||||
OstreeAsyncProgress *progress,
|
||||
gboolean *out_changed,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
rpmostree_sysroot_upgrader_pull_base (RpmOstreeSysrootUpgrader *self,
|
||||
const char *dir_to_pull,
|
||||
OstreeRepoPullFlags flags,
|
||||
OstreeAsyncProgress *progress,
|
||||
gboolean *out_changed,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
g_autofree char *origin_remote = NULL;
|
||||
g_autofree char *origin_ref = NULL;
|
||||
@ -775,12 +779,11 @@ finalize_overlays (RpmOstreeSysrootUpgrader *self,
|
||||
|
||||
static gboolean
|
||||
prepare_context_for_assembly (RpmOstreeSysrootUpgrader *self,
|
||||
RpmOstreeContext *ctx,
|
||||
const char *tmprootfs,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
DnfContext *hifctx = rpmostree_context_get_hif (ctx);
|
||||
DnfContext *hifctx = rpmostree_context_get_hif (self->ctx);
|
||||
|
||||
const char *sysroot_path =
|
||||
gs_file_get_path_cached (ostree_sysroot_get_path (self->sysroot));
|
||||
@ -800,7 +803,7 @@ prepare_context_for_assembly (RpmOstreeSysrootUpgrader *self,
|
||||
dnf_context_set_source_root (hifctx, tmprootfs);
|
||||
|
||||
/* point the core to the passwd & group of the merge deployment */
|
||||
rpmostree_context_set_passwd_dir (ctx, passwddir);
|
||||
rpmostree_context_set_passwd_dir (self->ctx, passwddir);
|
||||
|
||||
/* load the sepolicy to use during import */
|
||||
glnx_unref_object OstreeSePolicy *sepolicy = NULL;
|
||||
@ -808,19 +811,21 @@ prepare_context_for_assembly (RpmOstreeSysrootUpgrader *self,
|
||||
cancellable, error))
|
||||
return FALSE;
|
||||
|
||||
rpmostree_context_set_sepolicy (ctx, sepolicy);
|
||||
rpmostree_context_set_sepolicy (self->ctx, sepolicy);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* Initialize libdnf context from our configuration */
|
||||
static gboolean
|
||||
do_local_assembly (RpmOstreeSysrootUpgrader *self,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
prep_local_assembly (RpmOstreeSysrootUpgrader *self,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
g_autoptr(RpmOstreeContext) ctx = rpmostree_context_new_system (cancellable, error);
|
||||
g_assert (!self->ctx);
|
||||
self->ctx = rpmostree_context_new_system (cancellable, error);
|
||||
g_autofree char *tmprootfs_abspath = glnx_fdrel_abspath (self->tmprootfs_dfd, ".");
|
||||
|
||||
if (!prepare_context_for_assembly (self, ctx, tmprootfs_abspath, cancellable, error))
|
||||
if (!prepare_context_for_assembly (self, tmprootfs_abspath, cancellable, error))
|
||||
return FALSE;
|
||||
|
||||
GHashTable *local_pkgs = rpmostree_origin_get_local_packages (self->origin);
|
||||
@ -832,14 +837,15 @@ do_local_assembly (RpmOstreeSysrootUpgrader *self,
|
||||
if (treespec == NULL)
|
||||
return FALSE;
|
||||
|
||||
if (!rpmostree_context_setup (ctx, tmprootfs_abspath, tmprootfs_abspath, treespec, cancellable, error))
|
||||
if (!rpmostree_context_setup (self->ctx, tmprootfs_abspath, tmprootfs_abspath, treespec,
|
||||
cancellable, error))
|
||||
return FALSE;
|
||||
|
||||
g_autoptr(OstreeRepo) pkgcache_repo = NULL;
|
||||
if (!rpmostree_get_pkgcache_repo (self->repo, &pkgcache_repo, cancellable, error))
|
||||
return FALSE;
|
||||
|
||||
rpmostree_context_set_repos (ctx, self->repo, pkgcache_repo);
|
||||
rpmostree_context_set_repos (self->ctx, self->repo, pkgcache_repo);
|
||||
|
||||
const gboolean have_packages = (self->overlay_packages->len > 0 ||
|
||||
g_hash_table_size (local_pkgs) > 0 ||
|
||||
@ -847,26 +853,68 @@ do_local_assembly (RpmOstreeSysrootUpgrader *self,
|
||||
self->override_replace_local_packages->len > 0);
|
||||
if (have_packages)
|
||||
{
|
||||
if (!rpmostree_context_prepare (ctx, cancellable, error))
|
||||
if (!rpmostree_context_prepare (self->ctx, cancellable, error))
|
||||
return FALSE;
|
||||
self->layering_type = RPMOSTREE_SYSROOT_UPGRADER_LAYERING_RPMMD_REPOS;
|
||||
}
|
||||
else
|
||||
rpmostree_context_set_is_empty (ctx);
|
||||
{
|
||||
rpmostree_context_set_is_empty (self->ctx);
|
||||
self->layering_type = RPMOSTREE_SYSROOT_UPGRADER_LAYERING_LOCAL;
|
||||
}
|
||||
|
||||
if (self->flags & RPMOSTREE_SYSROOT_UPGRADER_FLAGS_DRY_RUN)
|
||||
{
|
||||
if (have_packages)
|
||||
rpmostree_print_transaction (rpmostree_context_get_hif (ctx));
|
||||
return TRUE; /* Note early return */
|
||||
rpmostree_print_transaction (rpmostree_context_get_hif (self->ctx));
|
||||
}
|
||||
|
||||
if (have_packages)
|
||||
/* If the current state has layering, compare the depsolved set for changes. */
|
||||
if (self->final_revision)
|
||||
{
|
||||
if (!rpmostree_context_download (ctx, cancellable, error))
|
||||
g_autoptr(GVariant) prev_commit = NULL;
|
||||
|
||||
if (!ostree_repo_load_variant (self->repo, OSTREE_OBJECT_TYPE_COMMIT,
|
||||
self->final_revision, &prev_commit, error))
|
||||
return FALSE;
|
||||
if (!rpmostree_context_import (ctx, cancellable, error))
|
||||
|
||||
g_autoptr(GVariant) metadata = g_variant_get_child_value (prev_commit, 0);
|
||||
g_autoptr(GVariantDict) metadata_dict = g_variant_dict_new (metadata);
|
||||
g_autoptr(GVariant) previous_sha512_v =
|
||||
_rpmostree_vardict_lookup_value_required (metadata_dict, "rpmostree.state-sha512",
|
||||
(GVariantType*)"s", error);
|
||||
if (!previous_sha512_v)
|
||||
return FALSE;
|
||||
if (!rpmostree_context_relabel (ctx, cancellable, error))
|
||||
const char *previous_state_sha512 = g_variant_get_string (previous_sha512_v, NULL);
|
||||
g_autofree char *new_state_sha512 = rpmostree_context_get_state_sha512 (self->ctx);
|
||||
|
||||
self->layering_changed = strcmp (previous_state_sha512, new_state_sha512) != 0;
|
||||
}
|
||||
else
|
||||
/* Otherwise, we're transitioning from not-layered to layered, so it
|
||||
definitely changed */
|
||||
self->layering_changed = TRUE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* Download packages, overlay, run scripts, and commit final rootfs to ostree */
|
||||
static gboolean
|
||||
perform_local_assembly (RpmOstreeSysrootUpgrader *self,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
/* If we computed no layering is required, we're done */
|
||||
if (self->layering_type == RPMOSTREE_SYSROOT_UPGRADER_LAYERING_NONE)
|
||||
return TRUE;
|
||||
|
||||
if (self->layering_type == RPMOSTREE_SYSROOT_UPGRADER_LAYERING_RPMMD_REPOS)
|
||||
{
|
||||
if (!rpmostree_context_download (self->ctx, cancellable, error))
|
||||
return FALSE;
|
||||
if (!rpmostree_context_import (self->ctx, cancellable, error))
|
||||
return FALSE;
|
||||
if (!rpmostree_context_relabel (self->ctx, cancellable, error))
|
||||
return FALSE;
|
||||
|
||||
g_clear_pointer (&self->final_revision, g_free);
|
||||
@ -874,7 +922,7 @@ do_local_assembly (RpmOstreeSysrootUpgrader *self,
|
||||
(self->flags & RPMOSTREE_SYSROOT_UPGRADER_FLAGS_PKGOVERLAY_NOSCRIPTS) > 0;
|
||||
|
||||
/* --- override/overlay and commit --- */
|
||||
if (!rpmostree_context_assemble_tmprootfs (ctx, self->tmprootfs_dfd,
|
||||
if (!rpmostree_context_assemble_tmprootfs (self->ctx, self->tmprootfs_dfd,
|
||||
self->devino_cache, noscripts,
|
||||
cancellable, error))
|
||||
return FALSE;
|
||||
@ -918,7 +966,7 @@ do_local_assembly (RpmOstreeSysrootUpgrader *self,
|
||||
rpmostree_output_task_end ("done");
|
||||
}
|
||||
|
||||
if (!rpmostree_context_commit_tmprootfs (ctx, self->tmprootfs_dfd, self->devino_cache,
|
||||
if (!rpmostree_context_commit_tmprootfs (self->ctx, self->tmprootfs_dfd, self->devino_cache,
|
||||
self->base_revision,
|
||||
RPMOSTREE_ASSEMBLE_TYPE_CLIENT_LAYERING,
|
||||
&self->final_revision,
|
||||
@ -947,29 +995,52 @@ requires_local_assembly (RpmOstreeSysrootUpgrader *self)
|
||||
rpmostree_origin_get_regenerate_initramfs (self->origin);
|
||||
}
|
||||
|
||||
/* Determines whether local assembly is required and does it if so. */
|
||||
static gboolean
|
||||
maybe_do_local_assembly (RpmOstreeSysrootUpgrader *self,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
/* Determine whether or not we require local modifications,
|
||||
* and if so, prepare layering (download rpm-md, depsolve etc).
|
||||
*/
|
||||
gboolean
|
||||
rpmostree_sysroot_upgrader_prep_layering (RpmOstreeSysrootUpgrader *self,
|
||||
RpmOstreeSysrootUpgraderLayeringType *out_layering,
|
||||
gboolean *out_changed,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
if (!checkout_base_tree (self, cancellable, error))
|
||||
return FALSE;
|
||||
/* Default to no assembly required, and not changed */
|
||||
self->layering_initialized = TRUE;
|
||||
self->layering_type = RPMOSTREE_SYSROOT_UPGRADER_LAYERING_NONE;
|
||||
*out_layering = self->layering_type;
|
||||
*out_changed = FALSE;
|
||||
|
||||
if (!finalize_overrides (self, cancellable, error))
|
||||
return FALSE;
|
||||
|
||||
if (!finalize_overlays (self, cancellable, error))
|
||||
return FALSE;
|
||||
|
||||
if (!requires_local_assembly (self))
|
||||
if (!rpmostree_origin_may_require_local_assembly (self->origin))
|
||||
{
|
||||
/* no assembly required; clear final_revision to ensure we deploy base */
|
||||
g_clear_pointer (&self->final_revision, g_free);
|
||||
/* No assembly? We're done then */
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return do_local_assembly (self, cancellable, error);
|
||||
/* Do a bit more work to see whether or not we have to do assembly */
|
||||
if (!checkout_base_tree (self, cancellable, error))
|
||||
return FALSE;
|
||||
if (!finalize_overrides (self, cancellable, error))
|
||||
return FALSE;
|
||||
if (!finalize_overlays (self, cancellable, error))
|
||||
return FALSE;
|
||||
|
||||
/* Recheck the state */
|
||||
if (!requires_local_assembly (self))
|
||||
{
|
||||
g_clear_pointer (&self->final_revision, g_free);
|
||||
/* No assembly? We're done then */
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* Actually do the prep work for local assembly */
|
||||
if (!prep_local_assembly (self, cancellable, error))
|
||||
return FALSE;
|
||||
|
||||
*out_layering = self->layering_type;
|
||||
*out_changed = self->layering_changed;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -986,29 +1057,32 @@ rpmostree_sysroot_upgrader_deploy (RpmOstreeSysrootUpgrader *self,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
glnx_unref_object OstreeDeployment *new_deployment = NULL;
|
||||
const char *target_revision;
|
||||
g_autoptr(GKeyFile) origin = NULL;
|
||||
|
||||
if (rpmostree_origin_may_require_local_assembly (self->origin))
|
||||
{
|
||||
if (!maybe_do_local_assembly (self, cancellable, error))
|
||||
return FALSE;
|
||||
}
|
||||
else
|
||||
g_clear_pointer (&self->final_revision, g_free);
|
||||
|
||||
if (self->flags & RPMOSTREE_SYSROOT_UPGRADER_FLAGS_DRY_RUN)
|
||||
{
|
||||
/* we already printed the transaction in do_final_local_assembly() */
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* Invoke prep_layering() if not done already */
|
||||
if (!self->layering_initialized)
|
||||
{
|
||||
RpmOstreeSysrootUpgraderLayeringType layering_type;
|
||||
gboolean layering_changed = FALSE;
|
||||
if (!rpmostree_sysroot_upgrader_prep_layering (self, &layering_type, &layering_changed,
|
||||
cancellable, error))
|
||||
return FALSE;
|
||||
}
|
||||
g_assert (self->layering_initialized);
|
||||
/* Generate the final ostree commit */
|
||||
if (!perform_local_assembly (self, cancellable, error))
|
||||
return FALSE;
|
||||
|
||||
/* make sure we have a known target to deploy */
|
||||
target_revision = self->final_revision ?: self->base_revision;
|
||||
const char *target_revision = self->final_revision ?: self->base_revision;
|
||||
g_assert (target_revision);
|
||||
|
||||
origin = rpmostree_origin_dup_keyfile (self->origin);
|
||||
g_autoptr(GKeyFile) origin = rpmostree_origin_dup_keyfile (self->origin);
|
||||
g_autoptr(OstreeDeployment) new_deployment = NULL;
|
||||
if (!ostree_sysroot_deploy_tree (self->sysroot, self->osname,
|
||||
target_revision, origin,
|
||||
self->cfg_merge_deployment,
|
||||
|
@ -53,6 +53,16 @@ typedef enum {
|
||||
RPMOSTREE_SYSROOT_UPGRADER_FLAGS_PKGOVERLAY_NOSCRIPTS = (1 << 4)
|
||||
} RpmOstreeSysrootUpgraderFlags;
|
||||
|
||||
/* _NONE means we're doing pure ostree, no client-side computation.
|
||||
* _LOCAL is just e.g. rpm-ostree initramfs
|
||||
* _RPMMD_REPOS is where we're downloading data from /etc/yum.repos.d
|
||||
*/
|
||||
typedef enum {
|
||||
RPMOSTREE_SYSROOT_UPGRADER_LAYERING_NONE = 0,
|
||||
RPMOSTREE_SYSROOT_UPGRADER_LAYERING_LOCAL = 1,
|
||||
RPMOSTREE_SYSROOT_UPGRADER_LAYERING_RPMMD_REPOS = 2,
|
||||
} RpmOstreeSysrootUpgraderLayeringType;
|
||||
|
||||
GType rpmostree_sysroot_upgrader_get_type (void);
|
||||
|
||||
GType rpmostree_sysroot_upgrader_flags_get_type (void);
|
||||
@ -76,13 +86,31 @@ const char *
|
||||
rpmostree_sysroot_upgrader_get_base (RpmOstreeSysrootUpgrader *self);
|
||||
|
||||
gboolean
|
||||
rpmostree_sysroot_upgrader_pull (RpmOstreeSysrootUpgrader *self,
|
||||
const char *dir_to_pull,
|
||||
OstreeRepoPullFlags flags,
|
||||
OstreeAsyncProgress *progress,
|
||||
gboolean *out_changed,
|
||||
GCancellable *cancellable,
|
||||
GError **error);
|
||||
rpmostree_sysroot_upgrader_pull_base (RpmOstreeSysrootUpgrader *self,
|
||||
const char *dir_to_pull,
|
||||
OstreeRepoPullFlags flags,
|
||||
OstreeAsyncProgress *progress,
|
||||
gboolean *out_changed,
|
||||
GCancellable *cancellable,
|
||||
GError **error);
|
||||
|
||||
gboolean
|
||||
rpmostree_sysroot_upgrader_prep_layering (RpmOstreeSysrootUpgrader *self,
|
||||
RpmOstreeSysrootUpgraderLayeringType *out_layering,
|
||||
gboolean *out_changed,
|
||||
GCancellable *cancellable,
|
||||
GError **error);
|
||||
|
||||
gboolean
|
||||
rpmostree_sysroot_upgrader_pull_repos (RpmOstreeSysrootUpgrader *self,
|
||||
const char *dir_to_pull,
|
||||
OstreeRepoPullFlags flags,
|
||||
OstreeAsyncProgress *progress,
|
||||
gboolean *out_changed,
|
||||
GCancellable *cancellable,
|
||||
GError **error);
|
||||
|
||||
|
||||
|
||||
gboolean
|
||||
rpmostree_sysroot_upgrader_deploy (RpmOstreeSysrootUpgrader *self,
|
||||
|
@ -221,13 +221,9 @@ package_diff_transaction_execute (RpmostreedTransaction *transaction,
|
||||
}
|
||||
|
||||
gboolean changed = FALSE;
|
||||
if (!rpmostree_sysroot_upgrader_pull (upgrader,
|
||||
"/usr/share/rpm",
|
||||
0,
|
||||
progress,
|
||||
&changed,
|
||||
cancellable,
|
||||
error))
|
||||
if (!rpmostree_sysroot_upgrader_pull_base (upgrader, "/usr/share/rpm",
|
||||
0, progress, &changed,
|
||||
cancellable, error))
|
||||
return FALSE;
|
||||
|
||||
rpmostree_transaction_emit_progress_end (RPMOSTREE_TRANSACTION (transaction));
|
||||
@ -818,8 +814,8 @@ deploy_transaction_execute (RpmostreedTransaction *transaction,
|
||||
{
|
||||
gboolean base_changed;
|
||||
|
||||
if (!rpmostree_sysroot_upgrader_pull (upgrader, NULL, 0, progress,
|
||||
&base_changed, cancellable, error))
|
||||
if (!rpmostree_sysroot_upgrader_pull_base (upgrader, NULL, 0, progress,
|
||||
&base_changed, cancellable, error))
|
||||
return FALSE;
|
||||
|
||||
changed = changed || base_changed;
|
||||
@ -870,6 +866,13 @@ deploy_transaction_execute (RpmostreedTransaction *transaction,
|
||||
changed = TRUE;
|
||||
}
|
||||
|
||||
RpmOstreeSysrootUpgraderLayeringType layering_type;
|
||||
gboolean layering_changed = FALSE;
|
||||
if (!rpmostree_sysroot_upgrader_prep_layering (upgrader, &layering_type, &layering_changed,
|
||||
cancellable, error))
|
||||
return FALSE;
|
||||
changed = changed || layering_changed;
|
||||
|
||||
rpmostree_transaction_emit_progress_end (RPMOSTREE_TRANSACTION (transaction));
|
||||
|
||||
/* TODO - better logic for "changed" based on deployments */
|
||||
|
@ -1459,6 +1459,7 @@ install_pkg_from_cache (RpmOstreeContext *self,
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* Check for/download new rpm-md, then depsolve */
|
||||
gboolean
|
||||
rpmostree_context_prepare (RpmOstreeContext *self,
|
||||
GCancellable *cancellable,
|
||||
|
@ -122,7 +122,6 @@ vm_rpmostree upgrade | tee output.txt
|
||||
assert_not_file_has_content output.txt '^Importing:'
|
||||
|
||||
# upgrade with different foo in repos --> should re-import
|
||||
vm_cmd ostree commit -b vmcheck --tree=ref=vmcheck
|
||||
c1=$(sha256sum ${test_tmpdir}/yumrepo/packages/x86_64/foo-1.0-1.x86_64.rpm)
|
||||
vm_build_rpm foo
|
||||
c2=$(sha256sum ${test_tmpdir}/yumrepo/packages/x86_64/foo-1.0-1.x86_64.rpm)
|
||||
|
Loading…
Reference in New Issue
Block a user