Skip to content

Commit

Permalink
Merge pull request #376 from foundriesio/check-app-bundle-integrity
Browse files Browse the repository at this point in the history
Check app installation along with app running
  • Loading branch information
mike-sul authored Dec 11, 2024
2 parents d22975e + ceadd80 commit 7442c0b
Show file tree
Hide file tree
Showing 3 changed files with 41 additions and 15 deletions.
2 changes: 1 addition & 1 deletion docker/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ FROM golang:1.22.2-bookworm AS composeapp
# Build composeapp
WORKDIR /build
RUN git clone https://github.com/foundriesio/composeapp.git && \
cd composeapp && git checkout c62494f56b123a411f7221f4ee87ed839d0930bd && make && cp ./bin/composectl /usr/bin/
cd composeapp && make && cp ./bin/composectl /usr/bin/


FROM ubuntu:jammy
Expand Down
41 changes: 38 additions & 3 deletions src/composeapp/appengine.cc
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ namespace composeapp {
enum class ExitCode { ExitCodeInsufficientSpace = 100 };

static bool checkAppStatus(const AppEngine::App& app, const Json::Value& status);
static bool checkAppInstallationStatus(const AppEngine::App& app, const Json::Value& status);
static bool isNullOrEmptyOrUnset(const Json::Value& val, const std::string& field);

AppEngine::Result AppEngine::fetch(const App& app) {
Result res{false};
Expand Down Expand Up @@ -66,10 +68,16 @@ bool AppEngine::isRunning(const App& app) const {
bool res{false};
try {
std::future<std::string> output;
exec(boost::format{"%s --store %s ps %s --format json"} % composectl_cmd_ % storeRoot() % app.uri, "",
boost::process::std_out > output);
exec(boost::format{"%s --store %s --compose %s ps %s --format json"} % composectl_cmd_ % storeRoot() %
installRoot() % app.uri,
"", boost::process::std_out > output);
const auto app_status{Utils::parseJSON(output.get())};
res = checkAppStatus(app, app_status);
// Make sure app images and bundle are properly installed
res = checkAppInstallationStatus(app, app_status);
if (res) {
// Make sure app is running
res = checkAppStatus(app, app_status);
}
} catch (const std::exception& exc) {
LOG_ERROR << "failed to verify whether app is running; app: " << app.name << ", err: " << exc.what();
}
Expand Down Expand Up @@ -227,4 +235,31 @@ static bool checkAppStatus(const AppEngine::App& app, const Json::Value& status)
return is_running;
}

static bool checkAppInstallationStatus(const AppEngine::App& app, const Json::Value& status) {
const auto& app_status{status.get(app.uri, Json::Value())};
if (!app_status.isObject()) {
LOG_ERROR << "could not get app status; uri: " << app.uri;
return false;
}
if (!isNullOrEmptyOrUnset(app_status, "missing_images")) {
LOG_INFO << app.name << " is not fully installed; missing images:\n" << app_status["missing_images"];
return false;
}
if (!isNullOrEmptyOrUnset(app_status, "bundle_errors")) {
LOG_INFO << app.name << " is not fully installed; invalid bundle installation:\n" << app_status["bundle_errors"];
return false;
}
return true;
}

static bool isNullOrEmptyOrUnset(const Json::Value& val, const std::string& field) {
bool res{false};
if (val.isMember(field)) {
res = val[field].isNull() || val[field].empty();
} else {
res = true;
}
return res;
}

} // namespace composeapp
13 changes: 2 additions & 11 deletions src/composeappmanager.cc
Original file line number Diff line number Diff line change
Expand Up @@ -221,25 +221,16 @@ ComposeAppManager::AppsContainer ComposeAppManager::getAppsToUpdate(const Uptane
continue;
}

if (!boost::filesystem::exists(cfg_.apps_root / app_name) ||
!boost::filesystem::exists(cfg_.apps_root / app_name / Docker::ComposeAppEngine::ComposeFile)) {
// an App that is supposed to be installed has been removed somehow, let's install it again
apps_to_update.insert(app_pair);
apps_and_reasons[app_pair.first] = "missing installation, to be re-installed";
LOG_INFO << app_name << " will be re-installed";
continue;
}

LOG_DEBUG << app_name << " performing full status check";
if (!app_engine_->isRunning({app_name, app_pair.second})) {
// an App that is supposed to running is not running
// an App that is supposed to be running is not running or is not fully installed
apps_to_update.insert(app_pair);
apps_and_reasons[app_pair.first] = "not running";
LOG_INFO << app_name << " is not installed or not running; will be installed and started";
continue;
}
if (!app_engine_->isFetched({app_name, app_pair.second})) {
// an App that is supposed to be installed is not fully installed
// an App that is supposed to be installed is not fully fetched
apps_to_update.insert(app_pair);
apps_and_reasons[app_pair.first] = "not fetched";
LOG_INFO << app_name << " is not fully fetched; missing blobs will be fetched";
Expand Down

0 comments on commit 7442c0b

Please sign in to comment.