app: add --download-only option

To complement the new `--cache-only` option, add a `--download-only`
option. This does exactly what it says: we download the ostree, download
and import packages, but don't actually commit & deploy. This can be
used to effectively prime a follow-up `--cache-only` operation that can
be done during a more convenient/safer maintenance window.

I debated naming the two options `--pull-only` and `--deploy-only` like
the ostree equivalents. Though "pull" felt like the wrong word given
that it's associated more with ostree pulling but rpm-ostree also
downloads & imports RPMs. As for `--deploy-only` vs `--cache-only`, it
seems like `--cache-only` is a more accurate description of the
functionality (i.e. rather than describing an action, it describes a
mode). I also considered `--no-download` to make the synergy with
`--download-only` more obvious. Maybe that's better? Naming is hard...

Closes: #713

Closes: #1049
Approved by: cgwalters
This commit is contained in:
Jonathan Lebon 2017-10-13 13:22:15 +00:00 committed by Atomic Bot
parent 24c184af03
commit e49f7cdd81
17 changed files with 281 additions and 10 deletions

View File

@ -188,6 +188,14 @@ Boston, MA 02111-1307, USA.
perform the operation without trying to download the target
tree from the remote nor the latest packages.
</para>
<para>
<option>--download-only</option> to only download the target
ostree and layered RPMs without actually performing the
deployment. This can be used with a subsequent
<option>--cache-only</option> invocation to perform the
operation completely offline.
</para>
</listitem>
</varlistentry>
@ -218,6 +226,14 @@ Boston, MA 02111-1307, USA.
perform the operation without trying to download the latest
packages.
</para>
<para>
<option>--download-only</option> to only download the target
layered RPMs without actually performing the deployment.
This can be used with a subsequent
<option>--cache-only</option> invocation to perform the
operation completely offline.
</para>
</listitem>
</varlistentry>
@ -283,6 +299,14 @@ Boston, MA 02111-1307, USA.
tree from the remote nor the latest packages.
</para>
<para>
<option>--download-only</option> to only download the target
ostree and layered RPMs without actually performing the
deployment. This can be used with a subsequent
<option>--cache-only</option> invocation to perform the
operation completely offline.
</para>
</listitem>
</varlistentry>
@ -374,6 +398,14 @@ Boston, MA 02111-1307, USA.
perform the upgrade without trying to download the latest
tree from the remote nor the latest packages.
</para>
<para>
<option>--download-only</option> to only download the target
ostree and layered RPMs without actually performing the
deployment. This can be used with a subsequent
<option>--cache-only</option> invocation to perform the
operation completely offline.
</para>
</listitem>
</varlistentry>

View File

@ -31,6 +31,7 @@ static char *opt_osname;
static gboolean opt_reboot;
static gboolean opt_preview;
static gboolean opt_cache_only;
static gboolean opt_download_only;
static GOptionEntry option_entries[] = {
{ "os", 0, 0, G_OPTION_ARG_STRING, &opt_osname, "Operate on provided OSNAME", "OSNAME" },
@ -41,6 +42,7 @@ static GOptionEntry option_entries[] = {
* deprecate --check-diff. */
{ "preview", 0, 0, G_OPTION_ARG_NONE, &opt_preview, "Just preview package differences", NULL },
{ "cache-only", 'C', 0, G_OPTION_ARG_NONE, &opt_cache_only, "Do not download latest ostree and RPM data", NULL },
{ "download-only", 0, 0, G_OPTION_ARG_NONE, &opt_download_only, "Just download latest ostree and RPM data, don't deploy", NULL },
{ NULL }
};
@ -112,6 +114,7 @@ rpmostree_builtin_deploy (int argc,
rpmostree_get_options_variant (opt_reboot,
TRUE, /* allow-downgrade */
opt_cache_only,
opt_download_only,
FALSE, /* skip-purge */
FALSE, /* no-pull-base */
FALSE, /* dry-run */

View File

@ -36,6 +36,7 @@ static gboolean opt_skip_purge;
static char * opt_branch;
static char * opt_remote;
static gboolean opt_cache_only;
static gboolean opt_download_only;
static GOptionEntry option_entries[] = {
{ "os", 0, 0, G_OPTION_ARG_STRING, &opt_osname, "Operate on provided OSNAME", "OSNAME" },
@ -44,6 +45,7 @@ static GOptionEntry option_entries[] = {
{ "reboot", 'r', 0, G_OPTION_ARG_NONE, &opt_reboot, "Initiate a reboot after rebase is finished", NULL },
{ "skip-purge", 0, 0, G_OPTION_ARG_NONE, &opt_skip_purge, "Keep previous refspec after rebase", NULL },
{ "cache-only", 'C', 0, G_OPTION_ARG_NONE, &opt_cache_only, "Do not download latest ostree and RPM data", NULL },
{ "download-only", 0, 0, G_OPTION_ARG_NONE, &opt_download_only, "Just download latest ostree and RPM data, don't deploy", NULL },
{ NULL }
};
@ -117,6 +119,7 @@ rpmostree_builtin_rebase (int argc,
rpmostree_get_options_variant (opt_reboot,
TRUE, /* allow-downgrade */
opt_cache_only,
opt_download_only,
opt_skip_purge,
FALSE, /* no-pull-base */
FALSE, /* dry-run */

View File

@ -81,6 +81,7 @@ rpmostree_builtin_rollback (int argc,
rpmostree_get_options_variant (opt_reboot,
FALSE, /* allow-downgrade */
FALSE, /* cache-only */
FALSE, /* download-only */
FALSE, /* skip-purge */
FALSE, /* no-pull-base */
FALSE, /* dry-run */

View File

@ -38,6 +38,7 @@ static gboolean opt_preview;
static gboolean opt_check;
static gboolean opt_upgrade_unchanged_exit_77;
static gboolean opt_cache_only;
static gboolean opt_download_only;
/* "check-diff" is deprecated, replaced by "preview" */
static GOptionEntry option_entries[] = {
@ -48,6 +49,7 @@ static GOptionEntry option_entries[] = {
{ "preview", 0, 0, G_OPTION_ARG_NONE, &opt_preview, "Just preview package differences", NULL },
{ "check", 0, 0, G_OPTION_ARG_NONE, &opt_check, "Just check if an upgrade is available", NULL },
{ "cache-only", 'C', 0, G_OPTION_ARG_NONE, &opt_cache_only, "Do not download latest ostree and RPM data", NULL },
{ "download-only", 0, 0, G_OPTION_ARG_NONE, &opt_download_only, "Just download latest ostree and RPM data, don't deploy", NULL },
{ "upgrade-unchanged-exit-77", 0, 0, G_OPTION_ARG_NONE, &opt_upgrade_unchanged_exit_77, "If no upgrade is available, exit 77", NULL },
{ NULL }
};
@ -124,6 +126,7 @@ rpmostree_builtin_upgrade (int argc,
rpmostree_get_options_variant (opt_reboot,
opt_allow_downgrade,
opt_cache_only,
opt_download_only,
FALSE, /* skip-purge */
FALSE, /* no-pull-base */
FALSE, /* dry-run */

View File

@ -1066,6 +1066,7 @@ GVariant*
rpmostree_get_options_variant (gboolean reboot,
gboolean allow_downgrade,
gboolean cache_only,
gboolean download_only,
gboolean skip_purge,
gboolean no_pull_base,
gboolean dry_run,
@ -1076,6 +1077,7 @@ rpmostree_get_options_variant (gboolean reboot,
g_variant_dict_insert (&dict, "reboot", "b", reboot);
g_variant_dict_insert (&dict, "allow-downgrade", "b", allow_downgrade);
g_variant_dict_insert (&dict, "cache-only", "b", cache_only);
g_variant_dict_insert (&dict, "download-only", "b", download_only);
g_variant_dict_insert (&dict, "skip-purge", "b", skip_purge);
g_variant_dict_insert (&dict, "no-pull-base", "b", no_pull_base);
g_variant_dict_insert (&dict, "dry-run", "b", dry_run);

View File

@ -100,6 +100,7 @@ GVariant*
rpmostree_get_options_variant (gboolean reboot,
gboolean allow_downgrade,
gboolean cache_only,
gboolean download_only,
gboolean skip_purge,
gboolean no_pull_base,
gboolean dry_run,

View File

@ -66,6 +66,7 @@ handle_override (RPMOSTreeSysroot *sysroot_proxy,
rpmostree_get_options_variant (opt_reboot,
FALSE, /* allow-downgrade */
cache_only,
FALSE, /* download-only */
FALSE, /* skip-purge */
TRUE, /* no-pull-base */
opt_dry_run,

View File

@ -35,6 +35,7 @@ static gboolean opt_dry_run;
static gchar **opt_install;
static gchar **opt_uninstall;
static gboolean opt_cache_only;
static gboolean opt_download_only;
static GOptionEntry option_entries[] = {
{ "os", 0, 0, G_OPTION_ARG_STRING, &opt_osname, "Operate on provided OSNAME", "OSNAME" },
@ -51,6 +52,7 @@ static GOptionEntry uninstall_option_entry[] = {
static GOptionEntry install_option_entry[] = {
{ "uninstall", 0, 0, G_OPTION_ARG_STRING_ARRAY, &opt_uninstall, "Uninstall a package", "PKG" },
{ "cache-only", 'C', 0, G_OPTION_ARG_NONE, &opt_cache_only, "Do not download latest ostree and RPM data", NULL },
{ "download-only", 0, 0, G_OPTION_ARG_NONE, &opt_download_only, "Just download latest ostree and RPM data, don't deploy", NULL },
{ NULL }
};
@ -78,6 +80,7 @@ pkg_change (RPMOSTreeSysroot *sysroot_proxy,
rpmostree_get_options_variant (opt_reboot,
FALSE, /* allow-downgrade */
opt_cache_only,
opt_download_only,
FALSE, /* skip-purge */
TRUE, /* no-pull-base */
opt_dry_run,

View File

@ -263,6 +263,12 @@
modifiers are specified.
"cache-only" (type 'b')
Do not update rpmmd repo metadata cache or ostree refspec.
Not valid if "download-only" is specified.
"download-only" (type 'b')
Update rpmmd repo metadata cache and ostree refspec. Do not
perform any deployments. This is like "dry-run" except that
the latter does not download and import packages. Not valid
if "cache-only" is specified.
-->
<method name="UpdateDeployment">
<arg type="a{sv}" name="modifiers" direction="in"/>

View File

@ -77,6 +77,7 @@ struct RpmOstreeSysrootUpgrader {
gboolean layering_initialized; /* Whether layering_type is known */
RpmOstreeSysrootUpgraderLayeringType layering_type;
gboolean layering_changed; /* Whether changes to layering should result in a new commit */
gboolean pkgs_imported; /* Whether pkgs to be layered have been downloaded & imported */
char *base_revision; /* Non-layered replicated commit */
char *final_revision; /* Computed by layering; if NULL, only using base_revision */
};
@ -877,22 +878,21 @@ prep_local_assembly (RpmOstreeSysrootUpgrader *self,
return TRUE;
}
/* Download packages, overlay, run scripts, and commit final rootfs to ostree */
/* Overlay pkgs, run scripts, and commit final rootfs to ostree */
static gboolean
perform_local_assembly (RpmOstreeSysrootUpgrader *self,
GCancellable *cancellable,
GError **error)
{
g_assert (self->layering_initialized);
g_assert (self->pkgs_imported);
/* 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;
@ -1029,6 +1029,30 @@ rpmostree_sysroot_upgrader_prep_layering (RpmOstreeSysrootUpgrader *self,
return TRUE;
}
gboolean
rpmostree_sysroot_upgrader_import_pkgs (RpmOstreeSysrootUpgrader *self,
GCancellable *cancellable,
GError **error)
{
g_assert (self->layering_initialized);
g_assert (!self->pkgs_imported);
self->pkgs_imported = TRUE;
/* any layering actually required? */
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;
}
return TRUE;
}
/**
* rpmostree_sysroot_upgrader_deploy:
* @self: Self
@ -1058,7 +1082,13 @@ rpmostree_sysroot_upgrader_deploy (RpmOstreeSysrootUpgrader *self,
cancellable, error))
return FALSE;
}
g_assert (self->layering_initialized);
if (!self->pkgs_imported)
{
if (!rpmostree_sysroot_upgrader_import_pkgs (self, cancellable, error))
return FALSE;
}
/* Generate the final ostree commit */
if (!perform_local_assembly (self, cancellable, error))
return FALSE;

View File

@ -103,6 +103,11 @@ rpmostree_sysroot_upgrader_prep_layering (RpmOstreeSysrootUpgrader *self,
GCancellable *cancellable,
GError **error);
gboolean
rpmostree_sysroot_upgrader_import_pkgs (RpmOstreeSysrootUpgrader *self,
GCancellable *cancellable,
GError **error);
gboolean
rpmostree_sysroot_upgrader_pull_repos (RpmOstreeSysrootUpgrader *self,
const char *dir_to_pull,

View File

@ -548,6 +548,8 @@ deploy_flags_from_options (GVariant *options,
ret |= RPMOSTREE_TRANSACTION_DEPLOY_FLAG_NO_OVERRIDES;
if (vardict_lookup_bool (&dict, "cache-only", FALSE))
ret |= RPMOSTREE_TRANSACTION_DEPLOY_FLAG_CACHE_ONLY;
if (vardict_lookup_bool (&dict, "download-only", FALSE))
ret |= RPMOSTREE_TRANSACTION_DEPLOY_FLAG_DOWNLOAD_ONLY;
return ret;
}
@ -648,6 +650,9 @@ start_deployment_txn (GDBusMethodInvocation *invocation,
vardict_lookup_bool (&options_dict, "no-pull-base", FALSE))
return glnx_null_throw (error, "Can't specify no-pull-base if setting a "
"new refspec or revision");
if (vardict_lookup_bool (&options_dict, "cache-only", FALSE) &&
vardict_lookup_bool (&options_dict, "download-only", FALSE))
return glnx_null_throw (error, "Can't specify cache-only and download-only");
if (override_replace_pkgs)
return glnx_null_throw (error, "Non-local replacement overrides not implemented yet");

View File

@ -894,11 +894,26 @@ deploy_transaction_execute (RpmostreedTransaction *transaction,
return FALSE;
changed = changed || layering_changed;
if (layering_changed)
{
if (!rpmostree_sysroot_upgrader_import_pkgs (upgrader, cancellable, error))
return FALSE;
}
/* XXX: check if this is needed */
rpmostree_transaction_emit_progress_end (RPMOSTREE_TRANSACTION (transaction));
/* TODO - better logic for "changed" based on deployments */
if (changed || self->refspec)
{
/* Note early return; we stop short of actually writing the deployment */
if (self->flags & RPMOSTREE_TRANSACTION_DEPLOY_FLAG_DOWNLOAD_ONLY)
{
/* XXX: improve msg here; e.g. cache will be blown on next operation? */
rpmostreed_transaction_emit_message_printf (transaction, "Downloaded.");
return TRUE;
}
if (!rpmostree_sysroot_upgrader_deploy (upgrader, cancellable, error))
return FALSE;

View File

@ -55,6 +55,7 @@ typedef enum {
RPMOSTREE_TRANSACTION_DEPLOY_FLAG_DRY_RUN = (1 << 5),
RPMOSTREE_TRANSACTION_DEPLOY_FLAG_NO_OVERRIDES = (1 << 6),
RPMOSTREE_TRANSACTION_DEPLOY_FLAG_CACHE_ONLY = (1 << 7),
RPMOSTREE_TRANSACTION_DEPLOY_FLAG_DOWNLOAD_ONLY = (1 << 8),
} RpmOstreeTransactionDeployFlags;

View File

@ -0,0 +1,159 @@
#!/bin/bash
#
# Copyright (C) 2017 Red Hat Inc.
#
# This library 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 License, 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.
set -euo pipefail
. ${commondir}/libtest.sh
. ${commondir}/libvm.sh
set -x
# SUMMARY: basic sanity check of --download-only and --cache-only
# To truly test --download-only/--cache-only, we need to set up an ostree remote
# and a remote yum repo. We could use the same ostree repo here since
# my-remote:my-ref != my-ref, but let's be extra realistic by having two
# completely separate repos.
# seed with a first package so we have a valid repo there
vm_build_rpm_repo_mode skip foobar
vm_start_httpd vmcheck /tmp 8888
vm_rpmostree cleanup -m
cat > vmcheck-http.repo << EOF
[vmcheck-http]
name=vmcheck-http
baseurl=http://localhost:8888/vmcheck/yumrepo
gpgcheck=0
EOF
vm_send /etc/yum.repos.d vmcheck-http.repo
osname=$(vm_get_booted_deployment_info osname)
# use the var through /sysroot/ to make sure we always get hardlinks
remote_repo=/ostree/deploy/$osname/var/tmp/vmcheck/repo
REMOTE_OSTREE="vm_cmd ostree --repo=$remote_repo"
vm_cmd rm -rf $remote_repo
vm_cmd mkdir -p $remote_repo
$REMOTE_OSTREE init --mode=bare
$REMOTE_OSTREE pull-local /ostree/repo vmcheck
vm_cmd ostree remote delete --if-exists vmcheck_remote
vm_cmd ostree remote add --no-gpg-verify vmcheck_remote file://$remote_repo
go_offline() {
vm_cmd mv ${remote_repo}{,.bak}
vm_cmd mv /tmp/vmcheck/yumrepo{,.bak}
YUMREPO=/tmp/vmcheck/yumrepo.bak/packages/x86_64
}
go_online() {
vm_cmd mv /tmp/vmcheck/yumrepo{.bak,}
vm_cmd mv ${remote_repo}{.bak,}
YUMREPO=/tmp/vmcheck/yumrepo/packages/x86_64
}
# sanity check
go_offline
if vm_rpmostree makecache; then
assert_not_reached "able to reach moved yum repo?"
fi
if vm_rpmostree rebase --remote vmcheck_remote; then
assert_not_reached "able to reach moved ostree repo?"
fi
go_online
vm_rpmostree makecache
vm_rpmostree rebase --remote vmcheck_remote
vm_rpmostree cleanup -pm
echo "ok setup"
csum=$($REMOTE_OSTREE commit -b vmcheck --tree=ref=vmcheck)
vm_rpmostree rebase --remote vmcheck_remote --install foobar --download-only
vm_assert_status_jq ".deployments|length == 1" \
".deployments[0][\"booted\"] == true"
go_offline
vm_rpmostree rebase --remote vmcheck_remote --install foobar --cache-only
vm_assert_status_jq ".deployments|length == 2" \
".deployments[0][\"booted\"] == false" \
".deployments[1][\"booted\"] == true" \
".deployments[0][\"base-checksum\"] == \"$csum\"" \
".deployments[0][\"packages\"]|length == 1" \
".deployments[0][\"packages\"]|index(\"foobar\") >= 0"
go_online
echo "ok offline rebase & install"
rc=0
vm_rpmostree upgrade --upgrade-unchanged-exit-77 || rc=$?
assert_streq "$rc" "77"
vm_rpmostree upgrade -C --upgrade-unchanged-exit-77 || rc=$?
assert_streq "$rc" "77"
echo "ok check for change with --cache-only"
$REMOTE_OSTREE commit -b vmcheck --tree=ref=vmcheck --timestamp '"Oct 21 1988"'
vm_cmd ostree pull vmcheck_remote:vmcheck
if vm_rpmostree upgrade -C |& tee out.txt; then
assert_not_reached "upgraded to chronologically older commit"
fi
assert_file_has_content out.txt 'chronologically older'
vm_rpmostree upgrade -C --allow-downgrade
echo "ok --cache-only still checks commit timestamp"
if vm_rpmostree upgrade --cache-only --download-only; then
assert_not_reached "allowed --cache-only and --download-only?"
fi
echo "ok conflicting options"
vm_rpmostree cleanup -prmb
vm_assert_status_jq ".deployments|length == 1" \
".deployments[0][\"booted\"] == true"
vm_build_rpm_repo_mode skip barbaz
vm_rpmostree install --download-only foobar $YUMREPO/barbaz-1.0-1.x86_64.rpm
vm_assert_status_jq ".deployments|length == 1" \
".deployments[0][\"booted\"] == true"
go_offline
vm_rpmostree install --cache-only foobar $YUMREPO/barbaz-1.0-1.x86_64.rpm
go_online
vm_assert_status_jq ".deployments|length == 2" \
".deployments[0][\"booted\"] == false" \
".deployments[1][\"booted\"] == true" \
".deployments[0][\"requested-packages\"]|length == 1" \
".deployments[0][\"requested-local-packages\"]|length == 1"
echo "ok offline local RPM install"
# synthesize update with foobar and barbaz builtin
pending=$(vm_get_deployment_info 0 checksum)
$REMOTE_OSTREE pull-local /ostree/repo $pending
$REMOTE_OSTREE commit -b vmcheck --tree=ref=$pending
vm_rpmostree cleanup -prmb
vm_rpmostree rebase --remote vmcheck_remote
vm_build_rpm_repo_mode skip foobar version 2.0
vm_rpmostree ex override replace $YUMREPO/foobar-2.0-1.x86_64.rpm
csum=$($REMOTE_OSTREE commit -b vmcheck --tree=ref=vmcheck)
vm_rpmostree upgrade --download-only
vm_assert_status_jq \
".deployments[0][\"base-checksum\"] != \"$csum\"" \
'.deployments[0]["base-local-replacements"]|length == 1' \
'.deployments[0]["requested-base-local-replacements"]|length == 1'
go_offline
vm_rpmostree upgrade --cache-only
vm_assert_status_jq \
".deployments[0][\"base-checksum\"] == \"$csum\"" \
'.deployments[0]["base-local-replacements"]|length == 1' \
'.deployments[0]["requested-base-local-replacements"]|length == 1'
go_online
echo "ok offline upgrade with local RPM replacement"
vm_stop_httpd vmcheck

View File

@ -50,7 +50,7 @@ if [[ $origin != vmcheck ]]; then
fi
# delete whatever tmp refs the previous testsuite runs may have created
vm_cmd ostree refs vmcheck_tmp --delete
vm_cmd ostree refs vmcheck_tmp vmcheck_remote --delete
# we bring our own test repo and test packages, so let's neuter any repo that
# comes with the distro to help speed up rpm-ostree metadata fetching since we
@ -145,7 +145,7 @@ for tf in $(find . -name 'test-*.sh' | sort); do
# nuke all vmcheck and vmcheck_tmp refs and recreate vmcheck from orig
echo "Restoring original vmcheck commit" >> ${LOG}
vm_cmd ostree refs vmcheck vmcheck_tmp --delete
vm_cmd ostree refs vmcheck vmcheck_tmp vmcheck_remote --delete
vm_cmd ostree refs vmcheck_orig --create vmcheck &>> ${LOG}
# go back to the original vmcheck deployment if needed
@ -168,8 +168,9 @@ for tf in $(find . -name 'test-*.sh' | sort); do
vm_cmd rm /etc/yum.repos.d -rf
vm_cmd cp -r /etc/yum.repos.d{.tmp,}
# and clean up our test repo
vm_cmd rm -rf /tmp/vmcheck
# and clean up any leftovers from our tmp
osname=$(vm_get_booted_deployment_info osname)
vm_cmd rm -rf /ostree/deploy/$osname/var/tmp/vmcheck
done