Skip to content

Commit

Permalink
Allow customizing description of new snapshot
Browse files Browse the repository at this point in the history
Implements [gh##55].
  • Loading branch information
laenion committed Jul 13, 2022
1 parent c84cb99 commit 2a2117d
Show file tree
Hide file tree
Showing 8 changed files with 144 additions and 26 deletions.
135 changes: 116 additions & 19 deletions dbus/tukitd.c
Expand Up @@ -220,30 +220,90 @@ static void *execute_func(void *args) {
return (void*)(intptr_t) ret;
}

static int execute_common(sd_bus_message *m, void *userdata, sd_bus_error *ret_error, int reboot) {
static int transaction_execute(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
char *base;
const char *snapid = NULL;
char *description = NULL;
char *rebootmethod = "none";
pthread_t execute_thread;
struct execute_args exec_args;
TransactionEntry* activeTransaction = userdata;
int ret = 0;
char type;

if (reboot) {
ret = sd_bus_message_read(m, "sss", &base, &exec_args.command, &rebootmethod);
} else {
ret = sd_bus_message_read(m, "ss", &base, &exec_args.command);
}
if (ret < 0) {
if (sd_bus_message_read(m, "ss", &base, &exec_args.command) < 0) {
sd_bus_error_set_const(ret_error, "org.opensuse.tukit.Error", "Could not read execution parameters.");
return -1;
}
if ((ret = sd_bus_message_peek_type(m, &type, NULL)) < 0) {
sd_bus_error_set_const(ret_error, "org.opensuse.tukit.Error", "Could not look for option parameters.");
return -1;
}

if (ret > 0 && type == 's') {
if (sd_bus_message_read(m, "s", &rebootmethod) < 0) {
sd_bus_error_set_const(ret_error, "org.opensuse.tukit.Error", "Could not read reboot parameter.");
return -1;
}
}
if (ret > 0 && type == 'a') {
if (sd_bus_message_enter_container(m, 'a', "{sv}")) {
while (sd_bus_message_enter_container(m, 'e', "sv") > 0) {
char *optionname = NULL;
if (sd_bus_message_read(m, "s", &optionname) >= 0) {
if (strcmp(optionname, "Reboot") == 0) {
if (sd_bus_message_enter_container(m, 'v', "s") >= 0) {
if (sd_bus_message_read(m, "s", &rebootmethod) < 0) {
sd_bus_error_set_const(ret_error, "org.opensuse.tukit.Error", "Could not decode 'Reboot' option value.");
return -1;
}
} else {
sd_bus_error_set_const(ret_error, "org.opensuse.tukit.Error", "Could not open variant container.");
return -1;
}
} else if (strcmp(optionname, "Description") == 0) {
if (sd_bus_message_enter_container(m, 'v', "s") >= 0) {
if (sd_bus_message_read(m, "s", &description) < 0) {
sd_bus_error_set_const(ret_error, "org.opensuse.tukit.Error", "Could not decode 'Description' option value.");
return -1;
}
} else {
sd_bus_error_set_const(ret_error, "org.opensuse.tukit.Error", "Could not open variant container.");
return -1;
}
} else {
sd_bus_error_set_const(ret_error, "org.opensuse.tukit.Error", "Unknown option.");
return -1;
}
if (sd_bus_message_exit_container(m) < 0) {
sd_bus_error_set_const(ret_error, "org.opensuse.tukit.Error", "Could not close variant container.");
return -1;
}
} else {
sd_bus_error_set_const(ret_error, "org.opensuse.tukit.Error", "Could not decode option name.");
return -1;
}
if (sd_bus_message_exit_container(m) < 0) {
sd_bus_error_set_const(ret_error, "org.opensuse.tukit.Error", "Could not close dict entry container.");
return -1;
}
}
if (sd_bus_message_exit_container(m) < 0) {
sd_bus_error_set_const(ret_error, "org.opensuse.tukit.Error", "Could not close array container.");
return -1;
}
} else {
sd_bus_error_set_const(ret_error, "org.opensuse.tukit.Error", "Could not read options container.");
return -1;
}
}

struct tukit_tx* tx = tukit_new_tx();
if (tx == NULL) {
sd_bus_error_set_const(ret_error, "org.opensuse.tukit.Error", tukit_get_errmsg());
return -1;
}
if ((ret = tukit_tx_init(tx, base)) != 0) {
if ((ret = tukit_tx_init_with_desc(tx, base, description)) != 0) {
sd_bus_error_set_const(ret_error, "org.opensuse.tukit.Error", tukit_get_errmsg());
goto finish_execute;
}
Expand Down Expand Up @@ -296,30 +356,65 @@ static int execute_common(sd_bus_message *m, void *userdata, sd_bus_error *ret_e
return ret;
}

static int transaction_execute(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
return execute_common(m, userdata, ret_error, 0);
}

static int transaction_execute_reboot(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
return execute_common(m, userdata, ret_error, 1);
}

static int transaction_open(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
char *base;
char *desc = NULL;
const char *snapid;
int ret = 0;

if (sd_bus_message_read(m, "s", &base) < 0) {
sd_bus_error_set_const(ret_error, "org.opensuse.tukit.Error", "Could not read base snapshot identifier.");
return -1;
}
if (sd_bus_message_enter_container(m, 'a', "{sv}") > 0) {
while (sd_bus_message_enter_container(m, 'e', "sv") > 0) {
char *optionname = NULL;
if (sd_bus_message_read(m, "s", &optionname) >= 0) {
if (strcmp(optionname, "Description") == 0) {
if (sd_bus_message_enter_container(m, 'v', "s") >= 0) {
if (sd_bus_message_read(m, "s", &desc) < 0) {
sd_bus_error_set_const(ret_error, "org.opensuse.tukit.Error", "Could not decode 'Description' option value.");
return -1;
}
} else {
sd_bus_error_set_const(ret_error, "org.opensuse.tukit.Error", "Could not open variant container.");
return -1;
}
} else {
sd_bus_error_set_const(ret_error, "org.opensuse.tukit.Error", "Unknown option.");
return -1;
}
if (sd_bus_message_exit_container(m) < 0) {
sd_bus_error_set_const(ret_error, "org.opensuse.tukit.Error", "Could not close variant container.");
return -1;
}
} else {
sd_bus_error_set_const(ret_error, "org.opensuse.tukit.Error", "Could not decode option name.");
return -1;
}
if (sd_bus_message_exit_container(m) < 0) {
sd_bus_error_set_const(ret_error, "org.opensuse.tukit.Error", "Could not close dict entry container.");
return -1;
}
}
if (sd_bus_message_exit_container(m) < 0) {
sd_bus_error_set_const(ret_error, "org.opensuse.tukit.Error", "Could not close array container.");
return -1;
}
}
struct tukit_tx* tx = tukit_new_tx();
if (tx == NULL) {
sd_bus_error_set_const(ret_error, "org.opensuse.tukit.Error", tukit_get_errmsg());
return -1;
}
if ((ret = tukit_tx_init(tx, base)) != 0) {
sd_bus_error_set_const(ret_error, "org.opensuse.tukit.Error", tukit_get_errmsg());
if (desc) {
if ((ret = tukit_tx_init_with_desc(tx, base, desc)) != 0) {
sd_bus_error_set_const(ret_error, "org.opensuse.tukit.Error", tukit_get_errmsg());
}
} else {
if ((ret = tukit_tx_init(tx, base)) != 0) {
sd_bus_error_set_const(ret_error, "org.opensuse.tukit.Error", tukit_get_errmsg());
}
}
if (!ret) {
snapid = tukit_tx_get_snapshot(tx);
Expand Down Expand Up @@ -663,8 +758,10 @@ int event_handler(sd_event_source *s, const struct signalfd_siginfo *si, void *u
static const sd_bus_vtable tukit_transaction_vtable[] = {
SD_BUS_VTABLE_START(0),
SD_BUS_METHOD_WITH_ARGS("Execute", SD_BUS_ARGS("s", base, "s", command), SD_BUS_RESULT("s", snapshot), transaction_execute, 0),
SD_BUS_METHOD_WITH_ARGS("ExecuteAndReboot", SD_BUS_ARGS("s", base, "s", command, "s", rebootmethod), SD_BUS_RESULT("s", snapshot), transaction_execute_reboot, 0),
SD_BUS_METHOD_WITH_ARGS("ExecuteAndReboot", SD_BUS_ARGS("s", base, "s", command, "s", rebootmethod), SD_BUS_RESULT("s", snapshot), transaction_execute, 0),
SD_BUS_METHOD_WITH_ARGS("ExecuteWithOpts", SD_BUS_ARGS("s", base, "s", command, "a{sv}", options), SD_BUS_RESULT("s", snapshot), transaction_execute, 0),
SD_BUS_METHOD_WITH_ARGS("Open", SD_BUS_ARGS("s", base), SD_BUS_RESULT("s", snapshot), transaction_open, 0),
SD_BUS_METHOD_WITH_ARGS("OpenWithOpts", SD_BUS_ARGS("s", base, "a{sv}", options), SD_BUS_RESULT("s", snapshot), transaction_open, 0),
SD_BUS_METHOD_WITH_ARGS("Call", SD_BUS_ARGS("s", transaction, "s", command), SD_BUS_NO_RESULT, transaction_call, 0),
SD_BUS_METHOD_WITH_ARGS("CallExt", SD_BUS_ARGS("s", transaction, "s", command), SD_BUS_NO_RESULT, transaction_callext, 0),
SD_BUS_METHOD_WITH_ARGS("Close", SD_BUS_ARGS("s", transaction), SD_BUS_RESULT("i", ret), transaction_close, 0),
Expand Down
16 changes: 16 additions & 0 deletions lib/Bindings/CBindings.cpp
Expand Up @@ -51,6 +51,22 @@ int tukit_tx_init(tukit_tx tx, char* base) {
}
return 0;
}
int tukit_tx_init_with_desc(tukit_tx tx, char* base, char* description) {
Transaction* transaction = reinterpret_cast<Transaction*>(tx);
if (std::string(base).empty())
base=(char*)"active";
try {
if (description == nullptr)
transaction->init(base);
else
transaction->init(base, description);
} catch (const std::exception &e) {
fprintf(stderr, "ERROR: %s\n", e.what());
errmsg = e.what();
return -1;
}
return 0;
}
int tukit_tx_discard_if_unchanged(tukit_tx tx, int discard) {
Transaction* transaction = reinterpret_cast<Transaction*>(tx);
try {
Expand Down
1 change: 1 addition & 0 deletions lib/Bindings/libtukit.h
Expand Up @@ -27,6 +27,7 @@ typedef void* tukit_tx;
tukit_tx tukit_new_tx();
void tukit_free_tx(tukit_tx tx);
int tukit_tx_init(tukit_tx tx, char* base);
int tukit_tx_init_with_desc(tukit_tx tx, char* base, char* description);
int tukit_tx_discard_if_unchanged(tukit_tx tx, int discard);
int tukit_tx_resume(tukit_tx tx, char* id);
int tukit_tx_execute(tukit_tx tx, char* argv[], const char* output[]);
Expand Down
4 changes: 2 additions & 2 deletions lib/Snapshot/Snapper.cpp
Expand Up @@ -15,10 +15,10 @@ namespace TransactionalUpdate {

/* SnapshotManager methods */

std::unique_ptr<Snapshot> Snapper::create(std::string base) {
std::unique_ptr<Snapshot> Snapper::create(std::string base, std::string description) {
if (! std::filesystem::exists("/.snapshots/" + base + "/snapshot"))
throw std::invalid_argument{"Base snapshot '" + base + "' does not exist."};
snapshotId = callSnapper("create --from " + base + " --read-write --print-number --description 'Snapshot Update of #" + base + "' --userdata 'transactional-update-in-progress=yes'");
snapshotId = callSnapper("create --from " + base + " --read-write --print-number --description '" + description + "' --userdata 'transactional-update-in-progress=yes'");
Util::rtrim(snapshotId);
return std::make_unique<Snapper>(snapshotId);
}
Expand Down
2 changes: 1 addition & 1 deletion lib/Snapshot/Snapper.hpp
Expand Up @@ -31,7 +31,7 @@ class Snapper: public SnapshotManager, public Snapshot {

// SnapshotManager
Snapper(): Snapshot("") {};
std::unique_ptr<Snapshot> create(std::string base) override;
std::unique_ptr<Snapshot> create(std::string base, std::string description) override;
virtual std::unique_ptr<Snapshot> open(std::string id) override;
std::deque<std::map<std::string, std::string>> getList(std::string columns) override;
std::string getCurrent() override;
Expand Down
2 changes: 1 addition & 1 deletion lib/SnapshotManager.hpp
Expand Up @@ -33,7 +33,7 @@ class SnapshotManager
/* Internal methods */
SnapshotManager() = default;
virtual ~SnapshotManager() = default;
virtual std::unique_ptr<Snapshot> create(std::string base) = 0;
virtual std::unique_ptr<Snapshot> create(std::string base, std::string description) = 0;
virtual std::unique_ptr<Snapshot> open(std::string id) = 0;

/**
Expand Down
6 changes: 4 additions & 2 deletions lib/Transaction.cpp
Expand Up @@ -202,12 +202,14 @@ int Transaction::impl::inotifyAdd(const char *pathname, const struct stat *sbuf,
return 0;
}

void Transaction::init(std::string base) {
void Transaction::init(std::string base, std::optional<std::string> description) {
if (base == "active")
base = pImpl->snapshotMgr->getCurrent();
else if (base == "default")
base = pImpl->snapshotMgr->getDefault();
pImpl->snapshot = pImpl->snapshotMgr->create(base);
if (!description)
description = "Snapshot Update of #" + base;
pImpl->snapshot = pImpl->snapshotMgr->create(base, description.value());

tulog.info("Using snapshot " + base + " as base for new snapshot " + pImpl->snapshot->getUid() + ".");

Expand Down
4 changes: 3 additions & 1 deletion lib/Transaction.hpp
Expand Up @@ -14,6 +14,7 @@
#define T_U_TRANSACTION_H

#include <filesystem>
#include <optional>

namespace TransactionalUpdate {

Expand All @@ -38,6 +39,7 @@ class Transaction {
/**
* @brief Open a new transaction
* @param base Snapshot ID, "active" or "default"
* @param description (optional) allows to customize the description of the snapshot
*
* Create a new snapshot, based on the given @base.
* @base can be "active" to base the snapshot on the currently running system, "default" to
Expand All @@ -46,7 +48,7 @@ class Transaction {
*
* If @base is not set "active" will be used as the default.
*/
void init(std::string base);
void init(std::string base, std::optional<std::string> description = std::nullopt);

/**
* @brief Set flag to discard snapshots if no changes are detected
Expand Down

0 comments on commit 2a2117d

Please sign in to comment.