Skip to content

Commit

Permalink
httpserver-monitoring-api: stop using kernel internal C++ API
Browse files Browse the repository at this point in the history
When OSv kernel is built to hide most symbols but glibc ones, the
OSv applications like httpserver monitoring API can not function
corretly as they rely on number of internal C++ API.

This patch modifies httpserver monitoring API to stop using kernel
internal C++ API. It does so by replacing some of the calls to internal C++
symbols with new module C-style API symbols: for example, sched::with_all_threads()
with new osv_get_all_threads(). In other scenarios, we fall back to
standard glibc API: for example osv::current_mounts() is replaced with
getmntent_r() and related functions.

Finally, we link httpserver monitoring app with core/options.cc and
thus remove need to have those symbols exposed by the kernel.

Signed-off-by: Waldemar Kozaczuk <[email protected]>
  • Loading branch information
wkozaczuk committed Jan 19, 2022
1 parent da5385c commit 891bfcd
Show file tree
Hide file tree
Showing 9 changed files with 150 additions and 70 deletions.
42 changes: 31 additions & 11 deletions modules/httpserver-api/api/fs.cc
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@
*/

#include "fs.hh"
#include "osv/mount.h"
#include "json/formatter.hh"
#include "autogen/fs.json.hh"
#include <string>
#include <vector>
#include <sys/statvfs.h>
#include <mntent.h>

namespace httpserver {

Expand All @@ -23,9 +23,9 @@ using namespace std;
using namespace json;
using namespace fs_json;

static void fill_dfstat(DFStat& dfstat, const osv::mount_desc& mount, const struct statvfs& st) {
dfstat.filesystem = mount.special;
dfstat.mount = mount.path;
static void fill_dfstat(DFStat& dfstat, mntent* mount, const struct statvfs& st) {
dfstat.filesystem = mount->mnt_fsname;
dfstat.mount = mount->mnt_dir;
dfstat.btotal = st.f_blocks;
dfstat.bfree = st.f_bfree;
dfstat.ftotal = st.f_files;
Expand All @@ -46,21 +46,31 @@ void init(routes& routes) {
getDFStats.set_handler("json",
[](const_req req)
{
using namespace osv;
const std::string onemount = req.param.at("mount");
struct statvfs st;
httpserver::json::DFStat dfstat;
vector<httpserver::json::DFStat> dfstats;

for (mount_desc mount : osv::current_mounts()) {
if ((mount.type == "zfs" || mount.type == "rofs") && (onemount == "" || onemount == mount.path)) {
if (statvfs(mount.path.c_str(),&st) != 0) {
FILE *mounts_fp = setmntent("/proc/mounts", "r");
if (!mounts_fp) {
throw server_error_exception("failed to get mounts information");
}

struct mntent* mount;
mntent mnt;
char strings[4096];
while ((mount = getmntent_r(mounts_fp, &mnt, strings, sizeof(strings)))) {
std::string fstype(mount->mnt_type);
if ((fstype == "zfs" || fstype == "rofs") && (onemount == "" || onemount == mount->mnt_dir)) {
if (statvfs(mount->mnt_dir,&st) != 0) {
endmntent(mounts_fp);
throw not_found_exception("mount does not exist");
}
fill_dfstat(dfstat, mount, st);
dfstats.push_back(dfstat);
}
};
endmntent(mounts_fp);

// checking if a specific file system was requested and if we found it
if (onemount != "" && dfstats.size() == 0) {
Expand All @@ -76,14 +86,24 @@ void init(routes& routes) {
httpserver::json::DFStat dfstat;
vector<httpserver::json::DFStat> res;

for (osv::mount_desc mount : osv::current_mounts()) {
if (mount.type == "zfs" || mount.type == "rofs") {
if (statvfs(mount.path.c_str(),&st) == 0) {
FILE *mounts_fp = setmntent("/proc/mounts", "r");
if (!mounts_fp) {
throw server_error_exception("failed to get mounts information");
}

struct mntent* mount;
mntent mnt;
char strings[4096];
while ((mount = getmntent_r(mounts_fp, &mnt, strings, sizeof(strings)))) {
std::string fstype(mount->mnt_type);
if (fstype == "zfs" || fstype == "rofs") {
if (statvfs(mount->mnt_dir,&st) == 0) {
fill_dfstat(dfstat, mount, st);
res.push_back(dfstat);
}
}
}
endmntent(mounts_fp);
return res;
});

Expand Down
23 changes: 16 additions & 7 deletions modules/httpserver-api/api/hardware.cc
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,8 @@
#include "autogen/hardware.json.hh"
#include "processor.hh"
#include "cpuid.hh"
#include <osv/sched.hh>
#include <osv/firmware.hh>
#include <osv/hypervisor.hh>
#include <osv/osv_c_wrappers.h>
#include <sys/sysinfo.h>

namespace httpserver {

Expand All @@ -30,26 +29,36 @@ extern "C" void httpserver_plugin_register_routes(httpserver::routes* routes) {
}
#endif

static std::string from_c_string(char *c_str) {
if (c_str) {
std::string str(c_str);
free(c_str);
return str;
} else {
return std::string();
}
}

void init(routes& routes)
{
hardware_json_init_path("Hardware management API");

processorFeatures.set_handler([](const_req req)
{
return processor::features_str();
return from_c_string(osv_processor_features());
});

processorCount.set_handler([](const_req req)
{
return sched::cpus.size();
return get_nprocs();
});

firmware_vendor.set_handler([](const_req) {
return osv::firmware_vendor();
return from_c_string(osv_firmware_vendor());
});

hypervisor_name.set_handler([](const_req) {
return osv::hypervisor_name();
return from_c_string(osv_hypervisor_name());
});
}

Expand Down
19 changes: 13 additions & 6 deletions modules/httpserver-api/api/network.cc
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
#include "../libtools/network_interface.hh"
#include "exception.hh"
#include <vector>
#include <osv/clock.hh>
#include <time.h>

namespace httpserver {

Expand Down Expand Up @@ -57,13 +57,16 @@ void init(routes& routes)
network_json_init_path("Hardware management API");
network_json::listIfconfig.set_handler([](const_req req) {
vector<Interface> res;
auto time = duration_cast<microseconds>
(osv::clock::uptime::now().time_since_epoch()).count();
timespec time;
if (clock_gettime(CLOCK_BOOTTIME, &time)) {
return res;
}
auto time_mc = time.tv_sec * 1000000 + time.tv_nsec / 1000;
for (unsigned int i = 0; i <= number_of_interfaces(); i++) {
auto* ifp = get_interface_by_index(i);

if (ifp != nullptr) {
res.push_back(get_interface(get_interface_name(ifp), ifp, time));
res.push_back(get_interface(get_interface_name(ifp), ifp, time_mc));
}
}
return res;
Expand All @@ -76,8 +79,12 @@ void init(routes& routes)
if (ifp == nullptr) {
throw not_found_exception(string("Interface ") + name + " not found");
}
auto time = duration_cast<microseconds>(osv::clock::uptime::now().time_since_epoch()).count();
return get_interface(name, ifp, time);
timespec time;
if (clock_gettime(CLOCK_BOOTTIME, &time)) {
throw not_found_exception("Failed to get time");
}
auto time_mc = time.tv_sec * 1000000 + time.tv_nsec / 1000;
return get_interface(name, ifp, time_mc);
});

network_json::getRoute.set_handler([](const_req req) {
Expand Down
67 changes: 41 additions & 26 deletions modules/httpserver-api/api/os.cc
Original file line number Diff line number Diff line change
Expand Up @@ -6,23 +6,20 @@
*/

#include <sys/utsname.h>
#include <sys/time.h>
#include "os.hh"
#include "osv/version.hh"
#include "json/formatter.hh"
#include "autogen/os.json.hh"
#include <sys/sysinfo.h>
#include <time.h>
#include <osv/shutdown.hh>
#include <osv/power.hh>
#include <osv/debug.hh>
#include <osv/sched.hh>
#include <api/unistd.h>
#include <osv/commands.hh>
#include <osv/osv_c_wrappers.h>
#include <algorithm>
#include "../java-base/balloon/balloon_api.hh"

extern char debug_buffer[DEBUG_BUFFER_SIZE];

namespace httpserver {

namespace api {
Expand All @@ -39,6 +36,16 @@ extern "C" void httpserver_plugin_register_routes(httpserver::routes* routes) {
}
#endif

static std::string from_c_string(char *c_str) {
if (c_str) {
std::string str(c_str);
free(c_str);
return str;
} else {
return std::string();
}
}

void init(routes& routes)
{
os_json_init_path("OS core API");
Expand All @@ -48,7 +55,7 @@ void init(routes& routes)
});

os_version.set_handler([](const_req req) {
return osv::version();
return from_c_string(osv_version());
});

os_vendor.set_handler([](const_req req) {
Expand Down Expand Up @@ -103,7 +110,7 @@ void init(routes& routes)
#endif

os_dmesg.set_handler([](const_req req) {
return debug_buffer;
return osv_debug_buffer();
});

os_get_hostname.set_handler([](const_req req)
Expand All @@ -122,31 +129,39 @@ void init(routes& routes)
#endif

os_threads.set_handler([](const_req req) {
using namespace std::chrono;
httpserver::json::Threads threads;
threads.time_ms = duration_cast<milliseconds>
(osv::clock::wall::now().time_since_epoch()).count();
timeval timeofday;
if (gettimeofday(&timeofday, nullptr)) {
return threads;
}
threads.time_ms = timeofday.tv_sec * 1000 + timeofday.tv_usec / 1000;
httpserver::json::Thread thread;
sched::with_all_threads([&](sched::thread &t) {
thread.id = t.id();
thread.status = t.get_status();
auto tcpu = t.tcpu();
thread.cpu = tcpu ? tcpu->id : -1;
thread.cpu_ms = duration_cast<milliseconds>(t.thread_clock()).count();
thread.switches = t.stat_switches.get();
thread.migrations = t.stat_migrations.get();
thread.preemptions = t.stat_preemptions.get();
thread.name = t.name();
thread.priority = t.priority();
thread.stack_size = t.get_stack_info().size;
thread.status = t.get_status();
threads.list.push(thread);
});
osv_thread *osv_threads;
size_t threads_num;
if (!osv_get_all_threads(&osv_threads, &threads_num)) {
for (size_t i = 0; i < threads_num; i++) {
auto &t = osv_threads[i];
thread.id = t.id;
thread.status = t.status;
thread.cpu = t.cpu_id;
thread.cpu_ms = t.cpu_ms;
thread.switches = t.switches;
thread.migrations = t.migrations;
thread.preemptions = t.preemptions;
thread.name = t.name;
free(t.name);
thread.priority = t.priority;
thread.stack_size = t.stack_size;
thread.status = t.status;
threads.list.push(thread);
}
free(osv_threads);
}
return threads;
});

os_get_cmdline.set_handler([](const_req req) {
return osv::getcmdline();
return from_c_string(osv_cmdline());
});

#if !defined(MONITORING)
Expand Down
Loading

0 comments on commit 891bfcd

Please sign in to comment.