From fea786cb2d086865d83797c842d89b7352b27527 Mon Sep 17 00:00:00 2001 From: Colin Walters Date: Thu, 3 Mar 2016 13:49:54 -0500 Subject: [PATCH] lib: Add ostree_sysroot_load_if_changed() API This will allow daemons like rpm-ostree to detect if there are any new deployments efficiently, in combination with using inotify. If there are any changes, rpm-ostree wants publish them on DBus. While we're here, add some changes to start doing unit C testing of the sysroot API. --- Makefile-tests.am | 5 +- apidoc/ostree-sections.txt | 1 + src/libostree/libostree.sym | 1 + src/libostree/ostree-sysroot-private.h | 1 + src/libostree/ostree-sysroot.c | 40 +++++++++-- src/libostree/ostree-sysroot.h | 6 ++ tests/libostreetest.c | 34 ++++++++-- tests/libostreetest.h | 12 ++-- tests/test-basic-c.c | 11 +-- tests/test-sysroot-c.c | 92 ++++++++++++++++++++++++++ 10 files changed, 179 insertions(+), 24 deletions(-) create mode 100644 tests/test-sysroot-c.c diff --git a/Makefile-tests.am b/Makefile-tests.am index 61b9b66a..34bbb446 100644 --- a/Makefile-tests.am +++ b/Makefile-tests.am @@ -122,7 +122,7 @@ libreaddir_rand_la_LDFLAGS = -avoid-version test_programs = tests/test-varint tests/test-ot-unix-utils tests/test-bsdiff tests/test-mutable-tree \ tests/test-keyfile-utils tests/test-ot-opt-utils tests/test-ot-tool-util \ tests/test-gpg-verify-result tests/test-checksum tests/test-lzma tests/test-rollsum \ - tests/test-basic-c + tests/test-basic-c tests/test-sysroot-c # An interactive tool noinst_PROGRAMS += tests/test-rollsum-cli @@ -156,6 +156,9 @@ tests_test_mutable_tree_LDADD = $(TESTS_LDADD) tests_test_basic_c_CFLAGS = $(TESTS_CFLAGS) tests_test_basic_c_LDADD = $(TESTS_LDADD) +tests_test_sysroot_c_CFLAGS = $(TESTS_CFLAGS) +tests_test_sysroot_c_LDADD = $(TESTS_LDADD) + tests_test_ot_unix_utils_CFLAGS = $(TESTS_CFLAGS) tests_test_ot_unix_utils_LDADD = $(TESTS_LDADD) diff --git a/apidoc/ostree-sections.txt b/apidoc/ostree-sections.txt index ee4ba1c6..87c138d8 100644 --- a/apidoc/ostree-sections.txt +++ b/apidoc/ostree-sections.txt @@ -381,6 +381,7 @@ ostree_sysroot_new ostree_sysroot_new_default ostree_sysroot_get_path ostree_sysroot_load +ostree_sysroot_load_if_changed ostree_sysroot_lock ostree_sysroot_try_lock ostree_sysroot_lock_async diff --git a/src/libostree/libostree.sym b/src/libostree/libostree.sym index 03350176..a85f0dbb 100644 --- a/src/libostree/libostree.sym +++ b/src/libostree/libostree.sym @@ -317,4 +317,5 @@ global: ostree_repo_get_dfd; ostree_repo_list_refs_ext; ostree_sysroot_init_osname; + ostree_sysroot_load_if_changed; } LIBOSTREE_2016.3; diff --git a/src/libostree/ostree-sysroot-private.h b/src/libostree/ostree-sysroot-private.h index 356509ad..229893d2 100644 --- a/src/libostree/ostree-sysroot-private.h +++ b/src/libostree/ostree-sysroot-private.h @@ -49,6 +49,7 @@ struct OstreeSysroot { int bootversion; int subbootversion; OstreeDeployment *booted_deployment; + struct timespec loaded_ts; /* Only access through ostree_sysroot_get_repo() */ OstreeRepo *repo; diff --git a/src/libostree/ostree-sysroot.c b/src/libostree/ostree-sysroot.c index eb2b353d..b1220408 100644 --- a/src/libostree/ostree-sysroot.c +++ b/src/libostree/ostree-sysroot.c @@ -793,19 +793,24 @@ gboolean ostree_sysroot_load (OstreeSysroot *self, GCancellable *cancellable, GError **error) +{ + return ostree_sysroot_load_if_changed (self, NULL, cancellable, error); +} + +gboolean +ostree_sysroot_load_if_changed (OstreeSysroot *self, + gboolean *out_changed, + GCancellable *cancellable, + GError **error) { gboolean ret = FALSE; guint i; int bootversion = 0; int subbootversion = 0; + struct stat stbuf; g_autoptr(GPtrArray) boot_loader_configs = NULL; g_autoptr(GPtrArray) deployments = NULL; - g_clear_pointer (&self->deployments, g_ptr_array_unref); - g_clear_pointer (&self->booted_deployment, g_object_unref); - self->bootversion = -1; - self->subbootversion = -1; - if (!ensure_sysroot_fd (self, error)) goto out; @@ -816,6 +821,28 @@ ostree_sysroot_load (OstreeSysroot *self, cancellable, error)) goto out; + if (fstatat (self->sysroot_fd, "ostree/deploy", &stbuf, 0) < 0) + { + glnx_set_error_from_errno (error); + goto out; + } + + if (out_changed) + { + if (self->loaded_ts.tv_sec == stbuf.st_mtim.tv_sec && + self->loaded_ts.tv_nsec == stbuf.st_mtim.tv_nsec) + { + *out_changed = FALSE; + ret = TRUE; + goto out; + } + } + + g_clear_pointer (&self->deployments, g_ptr_array_unref); + g_clear_pointer (&self->booted_deployment, g_object_unref); + self->bootversion = -1; + self->subbootversion = -1; + if (!_ostree_sysroot_read_boot_loader_configs (self, bootversion, &boot_loader_configs, cancellable, error)) goto out; @@ -847,8 +874,11 @@ ostree_sysroot_load (OstreeSysroot *self, self->deployments = deployments; deployments = NULL; /* Transfer ownership */ self->loaded = TRUE; + self->loaded_ts = stbuf.st_mtim; ret = TRUE; + if (out_changed) + *out_changed = TRUE; out: return ret; } diff --git a/src/libostree/ostree-sysroot.h b/src/libostree/ostree-sysroot.h index cab59d0a..077862aa 100644 --- a/src/libostree/ostree-sysroot.h +++ b/src/libostree/ostree-sysroot.h @@ -51,6 +51,12 @@ gboolean ostree_sysroot_load (OstreeSysroot *self, GCancellable *cancellable, GError **error); +_OSTREE_PUBLIC +gboolean ostree_sysroot_load_if_changed (OstreeSysroot *self, + gboolean *out_changed, + GCancellable *cancellable, + GError **error); + _OSTREE_PUBLIC void ostree_sysroot_unload (OstreeSysroot *self); diff --git a/tests/libostreetest.c b/tests/libostreetest.c index 9ebebde0..58283368 100644 --- a/tests/libostreetest.c +++ b/tests/libostreetest.c @@ -60,23 +60,45 @@ run_libtest (const char *cmd, GError **error) return ret; } -gboolean -ot_test_setup_repo (OtTest *self, - GCancellable *cancellable, +OstreeRepo * +ot_test_setup_repo (GCancellable *cancellable, GError **error) { gboolean ret = FALSE; g_autoptr(GFile) repo_path = g_file_new_for_path ("repo"); + glnx_unref_object OstreeRepo* ret_repo = NULL; if (!run_libtest ("setup_test_repository", error)) goto out; - self->repo = ostree_repo_new (repo_path); + ret_repo = ostree_repo_new (repo_path); - if (!ostree_repo_open (self->repo, cancellable, error)) + if (!ostree_repo_open (ret_repo, cancellable, error)) goto out; ret = TRUE; out: - return ret; + if (ret) + return g_steal_pointer (&ret_repo); + return NULL; +} + +OstreeSysroot * +ot_test_setup_sysroot (GCancellable *cancellable, + GError **error) +{ + gboolean ret = FALSE; + g_autoptr(GFile) sysroot_path = g_file_new_for_path ("sysroot"); + glnx_unref_object OstreeSysroot *ret_sysroot = NULL; + + if (!run_libtest ("setup_os_repository \"archive-z2\" \"syslinux\"", error)) + goto out; + + ret_sysroot = ostree_sysroot_new (sysroot_path); + + ret = TRUE; + out: + if (ret) + return g_steal_pointer (&ret_sysroot); + return NULL; } diff --git a/tests/libostreetest.h b/tests/libostreetest.h index 2ab93481..eb9bb0b2 100644 --- a/tests/libostreetest.h +++ b/tests/libostreetest.h @@ -27,13 +27,11 @@ G_BEGIN_DECLS -typedef struct { - OstreeRepo *repo; - GSubprocess *shell; -} OtTest; -gboolean ot_test_setup_repo (OtTest *self, - GCancellable *cancellable, - GError **error); +OstreeRepo *ot_test_setup_repo (GCancellable *cancellable, + GError **error); + +OstreeSysroot *ot_test_setup_sysroot (GCancellable *cancellable, + GError **error); G_END_DECLS diff --git a/tests/test-basic-c.c b/tests/test-basic-c.c index e0bcf9f8..d5dcc811 100644 --- a/tests/test-basic-c.c +++ b/tests/test-basic-c.c @@ -30,21 +30,22 @@ static void test_repo_is_not_system (gconstpointer data) { - OtTest *self = (void*)data; - g_assert (!ostree_repo_is_system (self->repo)); + OstreeRepo *repo = (void*)data; + g_assert (!ostree_repo_is_system (repo)); } int main (int argc, char **argv) { g_autoptr(GError) error = NULL; - OtTest selfd = {NULL,}; + glnx_unref_object OstreeRepo *repo = NULL; g_test_init (&argc, &argv, NULL); - if (!ot_test_setup_repo (&selfd, NULL, &error)) + repo = ot_test_setup_repo (NULL, &error); + if (!repo) goto out; - g_test_add_data_func ("/repo-not-system", &selfd, test_repo_is_not_system); + g_test_add_data_func ("/repo-not-system", repo, test_repo_is_not_system); return g_test_run(); out: diff --git a/tests/test-sysroot-c.c b/tests/test-sysroot-c.c new file mode 100644 index 00000000..9c07faf4 --- /dev/null +++ b/tests/test-sysroot-c.c @@ -0,0 +1,92 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * + * Copyright (C) 2016 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. + */ + +#include "config.h" + +#include +#include +#include + +#include "libglnx.h" +#include "libostreetest.h" + +static gboolean +run_sync (const char *cmdline, GError **error) +{ + int estatus; + if (!g_spawn_command_line_sync (cmdline, NULL, NULL, &estatus, error)) + return FALSE; + if (!g_spawn_check_exit_status (estatus, error)) + return FALSE; + return TRUE; +} + +static void +test_sysroot_reload (gconstpointer data) +{ + OstreeSysroot *sysroot = (void*)data; + g_autoptr(GError) error = NULL; + gboolean changed; + + if (!ostree_sysroot_load (sysroot, NULL, &error)) + goto out; + + if (!ostree_sysroot_load_if_changed (sysroot, &changed, NULL, &error)) + goto out; + g_assert (!changed); + + if (!run_sync ("ostree --repo=sysroot/ostree/repo pull-local --remote=testos testos-repo testos/buildmaster/x86_64-runtime", &error)) + goto out; + + if (!run_sync ("ostree admin --sysroot=sysroot deploy --karg=root=LABEL=MOO --karg=quiet --os=testos testos:testos/buildmaster/x86_64-runtime", &error)) + goto out; + + if (!ostree_sysroot_load_if_changed (sysroot, &changed, NULL, &error)) + goto out; + g_assert (changed); + + if (!ostree_sysroot_load_if_changed (sysroot, &changed, NULL, &error)) + goto out; + g_assert (!changed); + + out: + if (error) + g_error ("%s", error->message); +} + +int main (int argc, char **argv) +{ + g_autoptr(GError) error = NULL; + glnx_unref_object OstreeSysroot *sysroot = NULL; + + g_test_init (&argc, &argv, NULL); + + sysroot = ot_test_setup_sysroot (NULL, &error); + if (!sysroot) + goto out; + + g_test_add_data_func ("/sysroot-reload", sysroot, test_sysroot_reload); + + return g_test_run(); + out: + if (error) + g_error ("%s", error->message); + return 1; +}