Skip to content
This repository has been archived by the owner on May 21, 2024. It is now read-only.

C API for UptaneCycle and campaigns #1263

Merged
merged 3 commits into from
Aug 2, 2019
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions include/libaktualizr-c.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#ifndef AKTUALIZR_LIBAKTUALIZRC_H
#define AKTUALIZR_LIBAKTUALIZRC_H

#ifdef __cplusplus
#include "primary/aktualizr.h"

using Campaign = campaign::Campaign;

extern "C" {
#else
typedef struct Aktualizr Aktualizr;
typedef struct Campaign Campaign;
#endif

Aktualizr *Aktualizr_create(const char *config_path);
int Aktualizr_initialize(Aktualizr *a);
int Aktualizr_uptane_cycle(Aktualizr *a);
void Aktualizr_destroy(Aktualizr *a);

Campaign *Aktualizr_campaign_check(Aktualizr *a);
int Aktualizr_campaign_accept(Aktualizr *a, Campaign *c);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's a bit annoying that we have to pass an Aktualizr instance to all of these. Would be handy if Campaign contained a pointer. But that might need changes in the C++ object, don't know if we want that.

Copy link
Contributor Author

@eu-siemann eu-siemann Jul 30, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see no problem in this, tbh. That's pretty much idiomatic C and is equivalent to Aktualizr->CampaignAccept(Campaign *c). If we do just a single arg here, I would expect our C++ API to also change to Campaign->Accept(). I'm not sure if it makes it nicer, though.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok I think you're right.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On second thought, maybe it's not a bad thing to make those calls members of Campaign object. This way, we would prevent passing a campaign_id that belongs to another Aktualizr instance (a hypothetical situation, but still). WDYT, @lbonn @patrickvacek @mike-sul ?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If it doesn't require changes to the C++ code, then that seems like the way to go. Even if it does, that seems to me to be a slightly better way to go.

int Aktualizr_campaign_postpone(Aktualizr *a, Campaign *c);
int Aktualizr_campaign_decline(Aktualizr *a, Campaign *c);
void Aktualizr_campaign_free(Campaign *c);

#ifdef __cplusplus
}
#endif

#endif //AKTUALIZR_LIBAKTUALIZR_H
1 change: 1 addition & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ if(BUILD_WITH_CODE_COVERAGE)
endif()

add_subdirectory("libaktualizr")
add_subdirectory("libaktualizr-c")
add_subdirectory("virtual_secondary")
add_subdirectory("sota_tools")
add_subdirectory("aktualizr_primary")
Expand Down
10 changes: 10 additions & 0 deletions src/libaktualizr-c/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
SET(TARGET_NAME aktualizr-c)
SET(SOURCES libaktualizr-c.cc)

add_library(${TARGET_NAME} SHARED ${SOURCES})
target_include_directories(${TARGET_NAME} PUBLIC ${PROJECT_SOURCE_DIR}/include)
target_link_libraries(${TARGET_NAME} PRIVATE aktualizr_static_lib ${AKTUALIZR_EXTERNAL_LIBS})

aktualizr_source_file_checks(${SOURCES})

add_subdirectory(test)
77 changes: 77 additions & 0 deletions src/libaktualizr-c/libaktualizr-c.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
#include "libaktualizr-c.h"

Aktualizr *Aktualizr_create(const char *config_path) {
Aktualizr *a;
try {
Config cfg(config_path);
a = new Aktualizr(cfg);
} catch (const std::exception &e) {
std::cerr << "Aktualizr_create exception: " << e.what() << std::endl;
return nullptr;
}
return a;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe, there will be a need/requirement to return some status/error code to am app using the C version of libaktualizr, otherwise the only way to find out what went wrong is by parsing stderr.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mike-sul Absolutely. But first, we'll need to make sure that exceptions thrown by libaktualizr are consistent and meaningful. I plan to work on that next.

}

int Aktualizr_initialize(Aktualizr *a) {
try {
a->Initialize();
} catch (const std::exception &e) {
std::cerr << "Aktualizr_initialize exception: " << e.what() << std::endl;
return -1;
}
return 0;
}

int Aktualizr_uptane_cycle(Aktualizr *a) {
try {
a->UptaneCycle();
} catch (const std::exception &e) {
std::cerr << "Uptane cycle exception: " << e.what() << std::endl;
return -1;
}
return 0;
}

void Aktualizr_destroy(Aktualizr *a) { delete a; }

Campaign *Aktualizr_campaign_check(Aktualizr *a) {
try {
auto r = a->CampaignCheck().get();
if (!r.campaigns.empty()) {
// We don't support multiple campaigns at the moment
return new Campaign(r.campaigns[0]);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it fair to assume there will never be multiple campaigns? It would indeed be confusing if there were, but a comment to state the assumption might be worthwhile.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not supported at the moment, so I think it's worth keeping it simple here. I'll add a comment.

}
} catch (const std::exception &e) {
std::cerr << "Campaign check exception: " << e.what() << std::endl;
return nullptr;
}
return nullptr;
}
int Aktualizr_campaign_accept(Aktualizr *a, Campaign *c) {
try {
a->CampaignControl(c->id, campaign::Cmd::Accept).get();
} catch (const std::exception &e) {
std::cerr << "Campaign accept exception: " << e.what() << std::endl;
return -1;
}
return 0;
}
int Aktualizr_campaign_postpone(Aktualizr *a, Campaign *c) {
try {
a->CampaignControl(c->id, campaign::Cmd::Postpone).get();
} catch (const std::exception &e) {
std::cerr << "Campaign postpone exception: " << e.what() << std::endl;
return -1;
}
return 0;
}
int Aktualizr_campaign_decline(Aktualizr *a, Campaign *c) {
try {
a->CampaignControl(c->id, campaign::Cmd::Decline).get();
} catch (const std::exception &e) {
std::cerr << "Campaign decline exception: " << e.what() << std::endl;
return -1;
}
return 0;
}
void Aktualizr_campaign_free(Campaign *c) { delete c; }
8 changes: 8 additions & 0 deletions src/libaktualizr-c/test/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
SET(TARGET_NAME api-test)
SET(SOURCES api-test.c)

add_executable(${TARGET_NAME} EXCLUDE_FROM_ALL ${SOURCES})
add_dependencies(build_tests ${TARGET_NAME})
target_link_libraries(${TARGET_NAME} aktualizr-c)

aktualizr_source_file_checks(${SOURCES})
44 changes: 44 additions & 0 deletions src/libaktualizr-c/test/api-test.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
#include <stdio.h>
#include <stdlib.h>

#include "libaktualizr-c.h"

int main(int argc, char **argv) {
Aktualizr *a;
Campaign *c;
int err;

if (argc != 2) {
fprintf(stderr, "Missing config file\nUsage:\n\t%s CONFIG_FILE\n", argv[0]);
return EXIT_FAILURE;
}

a = Aktualizr_create(argv[1]);
if (!a) {
return EXIT_FAILURE;
}

err = Aktualizr_initialize(a);
if (err) {
return EXIT_FAILURE;
}

c = Aktualizr_campaign_check(a);
if (c) {
printf("Accepting running campaign\n");
err = Aktualizr_campaign_accept(a, c);
Aktualizr_campaign_free(c);
if (err) {
return EXIT_FAILURE;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will the aktualizr instance be properly tear-downed and freed in this case as well as in case of line #23 ? Or it's not important taking into account that the process is going to die anyway ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It won't, I forgot how to write proper C ;) But I'm rewriting this piece anyway

}
}

err = Aktualizr_uptane_cycle(a);
if (err) {
return EXIT_FAILURE;
}

Aktualizr_destroy(a);

return EXIT_SUCCESS;
}