Skip to content

Commit

Permalink
sysroot: Add concept of deployment "pinning" 📌
Browse files Browse the repository at this point in the history
Example user story: Jane rebases her OS to a new major version N, and wants to
keep around N-1 even after a few upgrades for a while so she can easily roll
back. I plan to add `rpm-ostree rebase --pin` to opt-in to this for example.

Builds on the new `libostree-transient` group to store pinning state there.

Closes: #1460
  • Loading branch information
cgwalters committed Feb 26, 2018
1 parent 6e54bfe commit 4374dcf
Show file tree
Hide file tree
Showing 15 changed files with 323 additions and 1 deletion.
1 change: 1 addition & 0 deletions Makefile-man.am
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ ostree-admin-config-diff.1 ostree-admin-deploy.1 \
ostree-admin-init-fs.1 ostree-admin-instutil.1 ostree-admin-os-init.1 \
ostree-admin-status.1 ostree-admin-set-origin.1 ostree-admin-switch.1 \
ostree-admin-undeploy.1 ostree-admin-upgrade.1 ostree-admin-unlock.1 \
ostree-admin-pin.1 \
ostree-admin.1 ostree-cat.1 ostree-checkout.1 ostree-checksum.1 \
ostree-commit.1 ostree-export.1 ostree-gpg-sign.1 ostree-config.1 \
ostree-diff.1 ostree-fsck.1 ostree-init.1 ostree-log.1 ostree-ls.1 \
Expand Down
1 change: 1 addition & 0 deletions Makefile-ostree.am
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ ostree_SOURCES += \
src/ostree/ot-admin-builtin-set-origin.c \
src/ostree/ot-admin-builtin-status.c \
src/ostree/ot-admin-builtin-switch.c \
src/ostree/ot-admin-builtin-pin.c \
src/ostree/ot-admin-builtin-upgrade.c \
src/ostree/ot-admin-builtin-unlock.c \
src/ostree/ot-admin-builtins.h \
Expand Down
2 changes: 2 additions & 0 deletions apidoc/ostree-sections.txt
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,7 @@ ostree_deployment_get_bootconfig
ostree_deployment_get_origin
ostree_deployment_get_origin_relpath
ostree_deployment_get_unlocked
ostree_deployment_is_pinned
ostree_deployment_set_index
ostree_deployment_set_bootserial
ostree_deployment_set_bootconfig
Expand Down Expand Up @@ -509,6 +510,7 @@ ostree_sysroot_init_osname
ostree_sysroot_deployment_set_kargs
ostree_sysroot_deployment_set_mutable
ostree_sysroot_deployment_unlock
ostree_sysroot_deployment_set_pinned
ostree_sysroot_write_deployments
ostree_sysroot_write_deployments_with_options
ostree_sysroot_write_origin_file
Expand Down
31 changes: 31 additions & 0 deletions bash/ostree
Original file line number Diff line number Diff line change
Expand Up @@ -399,6 +399,37 @@ _ostree_admin_os_init() {
return 0
}

_ostree_admin_pin() {
local boolean_options="
$main_boolean_options
"

local options_with_args="
--sysroot
"

local options_with_args_glob=$( __ostree_to_extglob "$options_with_args" )

case "$prev" in
--sysroot)
__ostree_compreply_dirs_only
return 0
;;
$options_with_args_glob )
return 0
;;
esac

case "$cur" in
-*)
local all_options="$boolean_options $options_with_args"
__ostree_compreply_all_options
;;
esac

return 0
}

_ostree_admin_set_origin() {
local boolean_options="
$main_boolean_options
Expand Down
82 changes: 82 additions & 0 deletions man/ostree-admin-pin.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
<?xml version='1.0'?> <!--*-nxml-*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">

<!--
Copyright 2018 Red Hat
SPDX-License-Identifier: LGPL-2.0+
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.
-->

<refentry id="ostree">

<refentryinfo>
<title>ostree admin pin</title>
<productname>OSTree</productname>

<authorgroup>
<author>
<contrib>Developer</contrib>
<firstname>Colin</firstname>
<surname>Walters</surname>
<email>[email protected]</email>
</author>
</authorgroup>
</refentryinfo>

<refmeta>
<refentrytitle>ostree admin pin</refentrytitle>
<manvolnum>1</manvolnum>
</refmeta>

<refnamediv>
<refname>ostree-admin-pin</refname>
<refpurpose>Explicitly retain deployment at a given index</refpurpose>
</refnamediv>

<refsynopsisdiv>
<cmdsynopsis>
<command>ostree admin pin</command> <arg choice="req">INDEX</arg>
</cmdsynopsis>
</refsynopsisdiv>

<refsect1>
<title>Description</title>

<para>
Ensures the deployment at <literal>INDEX</literal>, will not be garbage
collected by default. This is termed "pinning". If the
<literal>-u</literal> option is provided, undoes a pinning operation.
</para>
</refsect1>

<refsect1>
<title>Options</title>

<variablelist>
<varlistentry>
<term><option>--unpin</option>,<option>-u</option></term>

<listitem><para>
Undoes a pinning operation.
</para></listitem>
</varlistentry>
</variablelist>
</refsect1>

</refentry>
2 changes: 2 additions & 0 deletions src/libostree/libostree-devel.sym
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
/* Add new symbols here. Release commits should copy this section into -released.sym. */
LIBOSTREE_2018.3 {
ostree_deployment_origin_remove_transient_state;
ostree_sysroot_deployment_set_pinned;
ostree_deployment_is_pinned;
} LIBOSTREE_2018.2;

/* Stub section for the stable release *after* this development one; don't
Expand Down
17 changes: 17 additions & 0 deletions src/libostree/ostree-deployment.c
Original file line number Diff line number Diff line change
Expand Up @@ -322,3 +322,20 @@ ostree_deployment_get_unlocked (OstreeDeployment *self)
{
return self->unlocked;
}

/**
* ostree_deployment_is_pinned:
* @self: Deployment
*
* See ostree_sysroot_deployment_set_pinned().
*
* Returns: `TRUE` if deployment will not be subject to GC
* Since: 2018.3
*/
gboolean
ostree_deployment_is_pinned (OstreeDeployment *self)
{
if (!self->origin)
return FALSE;
return g_key_file_get_boolean (self->origin, OSTREE_ORIGIN_TRANSIENT_GROUP, "pinned", NULL);
}
3 changes: 3 additions & 0 deletions src/libostree/ostree-deployment.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,9 @@ _OSTREE_PUBLIC
GKeyFile *ostree_deployment_get_origin (OstreeDeployment *self);


_OSTREE_PUBLIC
gboolean ostree_deployment_is_pinned (OstreeDeployment *self);

_OSTREE_PUBLIC
void ostree_deployment_set_index (OstreeDeployment *self, int index);
_OSTREE_PUBLIC
Expand Down
44 changes: 44 additions & 0 deletions src/libostree/ostree-sysroot.c
Original file line number Diff line number Diff line change
Expand Up @@ -1572,12 +1572,14 @@ ostree_sysroot_simple_write_deployment (OstreeSysroot *sysroot,

/* Retain deployment if:
* - we're explicitly asked to, or
* - it's pinned
* - the deployment is for another osname, or
* - we're keeping pending deployments and this is a pending deployment, or
* - this is the merge or boot deployment, or
* - we're keeping rollback deployments and this is a rollback deployment
*/
if (retain
|| ostree_deployment_is_pinned (deployment)
|| !osname_matches
|| (retain_pending && !passed_crossover)
|| (is_booted || is_merge)
Expand Down Expand Up @@ -1832,3 +1834,45 @@ ostree_sysroot_deployment_unlock (OstreeSysroot *self,

return TRUE;
}

/**
* ostree_sysroot_deployment_set_pinned:
* @self: Sysroot
* @deployment: A deployment
* @is_pinned: Whether or not deployment will be automatically GC'd
* @error: Error
*
* By default, deployments may be subject to garbage collection. Typical uses of
* libostree only retain at most 2 deployments. If @is_pinned is `TRUE`, a
* metadata bit will be set causing libostree to avoid automatic GC of the
* deployment. However, this is really an "advisory" note; it's still possible
* for e.g. older versions of libostree unaware of pinning to GC the deployment.
*
* This function does nothing and returns successfully if the deployment
* is already in the desired pinning state.
*
* Since: 2018.3
*/
gboolean
ostree_sysroot_deployment_set_pinned (OstreeSysroot *self,
OstreeDeployment *deployment,
gboolean is_pinned,
GError **error)
{
const gboolean current_pin = ostree_deployment_is_pinned (deployment);
if (is_pinned == current_pin)
return TRUE;

g_autoptr(OstreeDeployment) deployment_clone = ostree_deployment_clone (deployment);
GKeyFile *origin_clone = ostree_deployment_get_origin (deployment_clone);

if (is_pinned)
g_key_file_set_boolean (origin_clone, OSTREE_ORIGIN_TRANSIENT_GROUP, "pinned", TRUE);
else
g_key_file_remove_key (origin_clone, OSTREE_ORIGIN_TRANSIENT_GROUP, "pinned", NULL);

if (!ostree_sysroot_write_origin_file (self, deployment, origin_clone, NULL, error))
return FALSE;

return TRUE;
}
6 changes: 6 additions & 0 deletions src/libostree/ostree-sysroot.h
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,12 @@ gboolean ostree_sysroot_deployment_set_mutable (OstreeSysroot *self,
GCancellable *cancellable,
GError **error);

_OSTREE_PUBLIC
gboolean ostree_sysroot_deployment_set_pinned (OstreeSysroot *self,
OstreeDeployment *deployment,
gboolean is_pinned,
GError **error);

_OSTREE_PUBLIC
gboolean ostree_sysroot_deployment_unlock (OstreeSysroot *self,
OstreeDeployment *deployment,
Expand Down
80 changes: 80 additions & 0 deletions src/ostree/ot-admin-builtin-pin.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
/*
* Copyright (C) 2018 Colin Walters <[email protected]>
*
* SPDX-License-Identifier: LGPL-2.0+
*
* 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.
*/

#include "config.h"

#include <stdlib.h>

#include "ot-main.h"
#include "ot-admin-builtins.h"
#include "ot-admin-functions.h"
#include "ostree.h"
#include "otutil.h"

/* ATTENTION:
* Please remember to update the bash-completion script (bash/ostree) and
* man page (man/ostree-admin-pin.xml) when changing the option list.
*/

static gboolean opt_unpin;

static GOptionEntry options[] = {
{ "unpin", 'u', 0, G_OPTION_ARG_NONE, &opt_unpin, "Unset pin", NULL },
{ NULL }
};

gboolean
ot_admin_builtin_pin (int argc, char **argv, OstreeCommandInvocation *invocation, GCancellable *cancellable, GError **error)
{
g_autoptr(GOptionContext) context = g_option_context_new ("INDEX");
g_autoptr(OstreeSysroot) sysroot = NULL;
if (!ostree_admin_option_context_parse (context, options, &argc, &argv,
OSTREE_ADMIN_BUILTIN_FLAG_SUPERUSER,
invocation, &sysroot, cancellable, error))
return FALSE;

if (argc < 2)
{
ot_util_usage_error (context, "INDEX must be specified", error);
return FALSE;
}

const char *deploy_index_str = argv[1];
const int deploy_index = atoi (deploy_index_str);

g_autoptr(OstreeDeployment) target_deployment = ot_admin_get_indexed_deployment (sysroot, deploy_index, error);
if (!target_deployment)
return FALSE;


gboolean current_pin = ostree_deployment_is_pinned (target_deployment);
const gboolean desired_pin = !opt_unpin;
if (current_pin == desired_pin)
g_print ("Deployment is already %s\n", current_pin ? "pinned" : "unpinned");
else
{
if (!ostree_sysroot_deployment_set_pinned (sysroot, target_deployment, desired_pin, error))
return FALSE;
g_print ("Deployment is now %s\n", desired_pin ? "pinned" : "unpinned");
}

return TRUE;
}
2 changes: 2 additions & 0 deletions src/ostree/ot-admin-builtin-status.c
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,8 @@ ot_admin_builtin_status (int argc, char **argv, OstreeCommandInvocation *invocat
ostree_deployment_unlocked_state_to_string (unlocked),
red_bold_suffix);
}
if (ostree_deployment_is_pinned (deployment))
g_print (" Pinned: yes\n");
if (!origin)
g_print (" origin: none\n");
else
Expand Down
1 change: 1 addition & 0 deletions src/ostree/ot-admin-builtins.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ BUILTINPROTO(init_fs);
BUILTINPROTO(undeploy);
BUILTINPROTO(deploy);
BUILTINPROTO(cleanup);
BUILTINPROTO(pin);
BUILTINPROTO(unlock);
BUILTINPROTO(status);
BUILTINPROTO(set_origin);
Expand Down
3 changes: 3 additions & 0 deletions src/ostree/ot-builtin-admin.c
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,9 @@ static OstreeCommand admin_subcommands[] = {
{ "set-origin", OSTREE_BUILTIN_FLAG_NO_REPO,
ot_admin_builtin_set_origin,
"Set Origin and create a new origin file" },
{ "pin", OSTREE_BUILTIN_FLAG_NO_REPO,
ot_admin_builtin_pin,
"Change the \"pinning\" state of a deployment" },
{ "status", OSTREE_BUILTIN_FLAG_NO_REPO,
ot_admin_builtin_status,
"List deployments" },
Expand Down
Loading

0 comments on commit 4374dcf

Please sign in to comment.