]> git.ipfire.org Git - thirdparty/FORT-validator.git/commitdiff
Empty cache whenever Fort's version changes
authorAlberto Leiva Popper <ydahhrk@gmail.com>
Tue, 5 Dec 2023 21:16:21 +0000 (18:16 -0300)
committerAlberto Leiva Popper <ydahhrk@gmail.com>
Wed, 6 Dec 2023 17:48:08 +0000 (14:48 -0300)
Because people might have missed the release notes, and also because I
expect to keep improving the cache code, possibly in ways that are not
backwards compatible.

Case in point: I already had to tweak the TAL metadata file in the
previous commit.

I will probably downgrade this to something less aggressive later.

src/cache/local_cache.c
src/cache/local_cache.h
src/file.c
src/object/tal.c
test/cache/local_cache_test.c
test/tal_test.c

index 6cdb6e6bbf21848a7d0a502038969b180913233d..ae1e9d1d012f0b8f273ab55f9fc6d1919df37dc3 100644 (file)
@@ -6,6 +6,7 @@
 #include "alloc.h"
 #include "common.h"
 #include "config.h"
+#include "configure_ac.h"
 #include "file.h"
 #include "json_util.h"
 #include "log.h"
@@ -40,17 +41,117 @@ struct rpki_cache {
        time_t startup_ts; /* When we started the last validation */
 };
 
+#define CACHE_METAFILE "cache.json"
+#define TAGNAME_VERSION "fort-version"
+
+#define TAL_METAFILE "tal.json"
 #define TAGNAME_URL "url"
 #define TAGNAME_ATTEMPT_TS "attempt-timestamp"
 #define TAGNAME_ATTEMPT_ERR "attempt-result"
 #define TAGNAME_SUCCESS_TS "success-timestamp"
 #define TAGNAME_IS_NOTIF "is-rrdp-notification"
 
+static char *
+get_cache_metafile_name(void)
+{
+       struct path_builder pb;
+       int error;
+
+       error = pb_init_cache(&pb, NULL, CACHE_METAFILE);
+       if (error) {
+               pr_op_err("Cannot create path to " CACHE_METAFILE ": %s",
+                   strerror(error));
+               return NULL;
+       }
+
+       return pb.string;
+}
+
+void
+cache_setup(void)
+{
+       char *filename;
+       json_t *root;
+       json_error_t jerror;
+       char const *file_version;
+       int error;
+
+       filename = get_cache_metafile_name();
+       if (filename == NULL)
+               return;
+
+       root = json_load_file(filename, 0, &jerror);
+
+       if (root == NULL) {
+               if (json_error_code(&jerror) == json_error_cannot_open_file)
+                       pr_op_debug("%s does not exist.", filename);
+               else
+                       pr_op_err("Json parsing failure at %s (%d:%d): %s",
+                           filename, jerror.line, jerror.column, jerror.text);
+               goto invalid_cache;
+       }
+       if (json_typeof(root) != JSON_OBJECT) {
+               pr_op_err("The root tag of %s is not an object.", filename);
+               goto invalid_cache;
+       }
+
+       error = json_get_str(root, TAGNAME_VERSION, &file_version);
+       if (error) {
+               if (error > 0)
+                       pr_op_err("%s is missing the " TAGNAME_VERSION " tag.",
+                           filename);
+               goto invalid_cache;
+       }
+
+       if (strcmp(file_version, PACKAGE_VERSION) == 0)
+               goto end;
+
+invalid_cache:
+       pr_op_info("The cache appears to have been built by a different version of Fort. I'm going to clear it, just to be safe.");
+       file_rm_rf(config_get_local_repository());
+
+end:   json_decref(root);
+       free(filename);
+}
+
+void
+cache_teardown(void)
+{
+       static char const * const CONTENT = "{ \"" TAGNAME_VERSION "\": \""
+           PACKAGE_VERSION "\" }\n";
+
+       char *filename;
+       FILE *file = NULL;
+       int error;
+
+       filename = get_cache_metafile_name();
+       if (filename == NULL)
+               return;
+
+       file = fopen(filename, "w");
+       if (file == NULL)
+               goto fail;
+
+       if (fprintf(file, CONTENT) < 0)
+               goto fail;
+
+       free(filename);
+       fclose(file);
+       return;
+
+fail:
+       error = errno;
+       pr_op_err("Cannot write %s: %s", filename, strerror(error));
+       free(filename);
+       if (file != NULL)
+               fclose(file);
+}
+
 static char *
 get_json_filename(struct rpki_cache *cache)
 {
        struct path_builder pb;
-       return pb_init_cache(&pb, cache->tal, "metadata.json")
+       return pb_init_cache(&pb, cache->tal, TAL_METAFILE)
            ? NULL : pb.string;
 }
 
@@ -134,7 +235,7 @@ add_node(struct rpki_cache *cache, struct cache_node *node)
 }
 
 static void
-load_metadata_json(struct rpki_cache *cache)
+load_tal_json(struct rpki_cache *cache)
 {
        char *filename;
        json_t *root;
@@ -143,7 +244,7 @@ load_metadata_json(struct rpki_cache *cache)
        struct cache_node *node;
 
        /*
-        * Note: Loading metadata.json is one of few things Fort can fail at
+        * Note: Loading TAL_METAFILE is one of few things Fort can fail at
         * without killing itself. It's just a cache of a cache.
         */
 
@@ -151,6 +252,8 @@ load_metadata_json(struct rpki_cache *cache)
        if (filename == NULL)
                return;
 
+       pr_op_debug("Loading %s.", filename);
+
        root = json_load_file(filename, 0, &jerror);
 
        if (root == NULL) {
@@ -185,7 +288,7 @@ cache_create(char const *tal)
        cache->startup_ts = time(NULL);
        if (cache->startup_ts == (time_t) -1)
                pr_crit("time(NULL) returned (time_t) -1.");
-       load_metadata_json(cache);
+       load_tal_json(cache);
        return cache;
 }
 
@@ -221,7 +324,7 @@ cancel:
 }
 
 static json_t *
-build_metadata_json(struct rpki_cache *cache)
+build_tal_json(struct rpki_cache *cache)
 {
        struct cache_node *node, *tmp;
        json_t *root, *child;
@@ -245,12 +348,12 @@ build_metadata_json(struct rpki_cache *cache)
 }
 
 static void
-write_metadata_json(struct rpki_cache *cache)
+write_tal_json(struct rpki_cache *cache)
 {
        char *filename;
        struct json_t *json;
 
-       json = build_metadata_json(cache);
+       json = build_tal_json(cache);
        if (json == NULL)
                return;
 
@@ -736,7 +839,7 @@ delete_unknown_files(struct rpki_cache *cache)
        struct path_builder pb;
        int error;
 
-       error = pb_init_cache(&pb, cache->tal, "metadata.json");
+       error = pb_init_cache(&pb, cache->tal, TAL_METAFILE);
        if (error) {
                pr_op_err("Cannot delete unknown files from %s's cache: %s",
                    cache->tal, strerror(error));
@@ -799,7 +902,7 @@ cache_destroy(struct rpki_cache *cache)
        struct cache_node *node, *tmp;
 
        cache_cleanup(cache);
-       write_metadata_json(cache);
+       write_tal_json(cache);
 
        HASH_ITER(hh, cache->ht, node, tmp)
                delete_node(cache, node);
index 3b677fdbd22e3627cbcdebe64184d172ca41e392..d01932a5f79aff4e20295930c178fe2cd39b8ff0 100644 (file)
@@ -5,6 +5,9 @@
 
 struct rpki_cache;
 
+void cache_setup(void);
+void cache_teardown(void);
+
 struct rpki_cache *cache_create(char const *);
 /* Will destroy the cache object, but not the cache directory itself, obv. */
 void cache_destroy(struct rpki_cache *);
index 2cbc2e663af4923b212da0ee66fb6b17554e0686..40a2da8270f6a6efcaa5e04e999dea5f57ff86bc 100644 (file)
@@ -151,6 +151,7 @@ file_valid(char const *file_name)
 static int
 rm(const char *fpath, const struct stat *sb, int typeflag, struct FTW *ftwbuf)
 {
+       pr_op_debug("Deleting %s.", fpath);
        return (remove(fpath) != 0) ? errno : 0;
 }
 
index 2d0fe8d29c41c7fa614063bde4d75d5dc5ceceab..0f5ad1e981886eb1690767303c5f24d9a02e2c98 100644 (file)
@@ -507,6 +507,8 @@ perform_standalone_validation(void)
        struct db_table *db = NULL;
        int error, tmperr;
 
+       cache_setup();
+
        error = init_tmpdir();
        if (error) {
                pr_val_err("Cannot initialize the cache's temporal directory: %s",
@@ -551,6 +553,8 @@ perform_standalone_validation(void)
                thread_destroy(thread);
        }
 
+       cache_teardown();
+
        /* If one thread has errors, we can't keep the resulting table. */
        if (error) {
                db_table_destroy(db);
index 0491c7d472bb3359a16caffabd76d2be48267551..3cd53ae71ab1e6f4ecc764558f701a42c7d0471b 100644 (file)
@@ -712,7 +712,7 @@ START_TEST(test_dots)
 }
 END_TEST
 
-START_TEST(test_metadata_json)
+START_TEST(test_tal_json)
 {
        json_t *json;
        char *str;
@@ -728,8 +728,8 @@ START_TEST(test_metadata_json)
        add_node(cache, NODE("https://a/b", 1, 1, 0));
        add_node(cache, node("https://a/c", 0, 0, 1, 0, 1));
 
-       json = build_metadata_json(cache);
-       ck_assert_int_eq(0, json_dump_file(json, "tmp/" TAL_FILE "/metadata.json", JSON_COMPACT));
+       json = build_tal_json(cache);
+       ck_assert_int_eq(0, json_dump_file(json, "tmp/" TAL_FILE "/" TAL_METAFILE, JSON_COMPACT));
 
        str = json_dumps(json, /* JSON_INDENT(4) */ JSON_COMPACT);
        json_decref(json);
@@ -745,7 +745,7 @@ START_TEST(test_metadata_json)
 
        cache_reset(cache);
 
-       load_metadata_json(cache);
+       load_tal_json(cache);
        ck_assert_ptr_ne(NULL, cache->ht);
 
        validate_cache(0,
@@ -923,8 +923,8 @@ static Suite *thread_pool_suite(void)
        dot = tcase_create("dot");
        tcase_add_test(dot, test_dots);
 
-       meta = tcase_create("metadata.json");
-       tcase_add_test(meta, test_metadata_json);
+       meta = tcase_create(TAL_METAFILE);
+       tcase_add_test(meta, test_tal_json);
 
        recover = tcase_create("recover");
        tcase_add_test(recover, test_recover);
index b461ac4223617dc45a05ff17a3a52ac172e7a488..930bed7b0f75d191278a9a5d6688c6f3c3d75e68 100644 (file)
@@ -13,6 +13,7 @@
 
 /* Mocks */
 
+MOCK_ABORT_VOID(cache_setup, void)
 MOCK(cache_create, struct rpki_cache *, NULL, char const *tal)
 MOCK_VOID(cache_destroy, struct rpki_cache *cache)
 MOCK_ABORT_INT(cache_download, struct rpki_cache *cache, struct rpki_uri *uri,