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]> --- modules/httpserver-api/api/fs.cc | 42 ++++++++++---- modules/httpserver-api/api/hardware.cc | 23 +++++--- modules/httpserver-api/api/network.cc | 19 ++++-- modules/httpserver-api/api/os.cc | 67 +++++++++++++--------- modules/httpserver-api/global_server.cc | 34 +++++++---- modules/httpserver-api/global_server.hh | 5 ++ modules/httpserver-api/openssl-init.cc | 15 +++-- modules/httpserver-api/ssl_server.cc | 9 ++- modules/httpserver-monitoring-api/Makefile | 6 +- 9 files changed, 150 insertions(+), 70 deletions(-) diff --git a/modules/httpserver-api/api/fs.cc b/modules/httpserver-api/api/fs.cc index 94eec77b..52e58c39 100644 --- a/modules/httpserver-api/api/fs.cc +++ b/modules/httpserver-api/api/fs.cc @@ -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 { @@ -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; @@ -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) { @@ -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; }); diff --git a/modules/httpserver-api/api/hardware.cc b/modules/httpserver-api/api/hardware.cc index f023e394..fe069913 100644 --- a/modules/httpserver-api/api/hardware.cc +++ b/modules/httpserver-api/api/hardware.cc @@ -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 { @@ -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()); }); } diff --git a/modules/httpserver-api/api/network.cc b/modules/httpserver-api/api/network.cc index 7d31faf8..595faf4c 100644 --- a/modules/httpserver-api/api/network.cc +++ b/modules/httpserver-api/api/network.cc @@ -10,7 +10,7 @@ #include "../libtools/network_interface.hh" #include "exception.hh" #include <vector> -#include <osv/clock.hh> +#include <time.h> namespace httpserver { @@ -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; @@ -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) { diff --git a/modules/httpserver-api/api/os.cc b/modules/httpserver-api/api/os.cc index 036f9162..38a662a7 100644 --- a/modules/httpserver-api/api/os.cc +++ b/modules/httpserver-api/api/os.cc @@ -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 { @@ -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"); @@ -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) { @@ -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) @@ -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) diff --git a/modules/httpserver-api/global_server.cc b/modules/httpserver-api/global_server.cc index 5cf1c62e..649e62cf 100644 --- a/modules/httpserver-api/global_server.cc +++ b/modules/httpserver-api/global_server.cc @@ -8,15 +8,14 @@ #include "global_server.hh" #include "path_holder.hh" #include <iostream> -#include <osv/app.hh> #include <fstream> #include <dlfcn.h> #include <boost/filesystem.hpp> #include <boost/foreach.hpp> #include "json/api_docs.hh" -#include <osv/debug.h> #include "transformers.hh" #include <osv/options.hh> +#include <osv/osv_c_wrappers.h> #if !defined(MONITORING) #include "yaml-cpp/yaml.h" #else @@ -41,6 +40,13 @@ global_server& global_server::get() return *instance; } +void global_server::termination_handler() { + get().s->close(); + for( auto plugin : get().plugins) { + dlclose(plugin); + } +} + bool global_server::run(std::map<std::string,std::vector<std::string>>& _config) { if (get().s != nullptr) { @@ -107,12 +113,7 @@ bool global_server::run(std::map<std::string,std::vector<std::string>>& _config) auto port = get().config["port"][0]; get().s = new http::server::server(get().config, &get()._routes); - osv::this_application::on_termination_request([&] { - get().s->close(); - for( auto plugin : get().plugins) { - dlclose(plugin); - } - }); + osv_current_app_on_termination_request(termination_handler); std::cout << "Rest API server running on port " << port << std::endl; get().s->run(); @@ -121,6 +122,7 @@ bool global_server::run(std::map<std::string,std::vector<std::string>>& _config) #if !defined(MONITORING) void global_server::setup_file_mappings(const YAML::Node& file_mappings_node) { + auto debug_enabled = osv_debug_enabled(); for (auto node : file_mappings_node) { const YAML::Node path = node["path"]; if (path && node["directory"]) { @@ -130,7 +132,9 @@ void global_server::setup_file_mappings(const YAML::Node& file_mappings_node) { new directory_handler(directory, new content_replace(content_replace_node.as<std::string>())) : new directory_handler(directory); _routes.add(GET, url(path.as<std::string>()).remainder("path"), handler); - debug("httpserver: setup directory mapping: [%s] -> [%s]\n", path.as<std::string>().c_str(), directory.c_str()); + if (debug_enabled) { + std::cout << "httpserver: setup directory mapping: [" << path.as<std::string>() << "] -> [" << directory << "]" << std::endl; + } } else if (path && node["file"]) { const std::string file = node["file"].as<std::string>(); @@ -142,7 +146,9 @@ void global_server::setup_file_mappings(const YAML::Node& file_mappings_node) { else { _routes.add(GET, url(path.as<std::string>()).remainder("path"), handler); } - debug("httpserver: setup file mapping: [%s] -> [%s]\n", path.as<std::string>().c_str(), file.c_str()); + if (debug_enabled) { + std::cout << "httpserver: setup file mapping: [" << path.as<std::string>() << "] -> [" << file << "]" << std::endl; + } } } } @@ -165,7 +171,9 @@ void global_server::setup_redirects(const YAML::Node& redirects_node) { return ""; }); _routes.put(GET, path, redirect); - debug("httpserver: setup redirect: [%s] -> [%s]\n", path.c_str(), target_path.c_str()); + if (osv_debug_enabled()) { + std::cout << "httpserver: setup redirect: [" << path << "] -> [" << target_path << "]" << std::endl; + } } } } @@ -242,6 +250,8 @@ void global_server::load_plugin(const std::string& path) } plugins.push_back(plugin); httpserver_plugin_register_routes(&_routes); - debug("httpserver: loaded plugin from path: %s\n",path.c_str()); + if (osv_debug_enabled()) { + std::cout << "httpserver: loaded plugin from path: " << path << std::endl; + } } } diff --git a/modules/httpserver-api/global_server.hh b/modules/httpserver-api/global_server.hh index e70b7854..587860fb 100644 --- a/modules/httpserver-api/global_server.hh +++ b/modules/httpserver-api/global_server.hh @@ -29,6 +29,11 @@ public: */ static global_server& get(); + /** + * cleanup routine: shutdown server and close all plugins + */ + static void termination_handler(); + /** * get the route object * @return a reference to the route object diff --git a/modules/httpserver-api/openssl-init.cc b/modules/httpserver-api/openssl-init.cc index 8630d019..a1bed2bd 100644 --- a/modules/httpserver-api/openssl-init.cc +++ b/modules/httpserver-api/openssl-init.cc @@ -8,7 +8,7 @@ #include <iostream> #include <fstream> #include <mutex> -#include <osv/debug.hh> +#include <osv/osv_c_wrappers.h> #include <assert.h> #include <openssl/rand.h> @@ -16,9 +16,16 @@ #include "openssl-init.hh" +static void debug_line(const char *line) { + auto debug_enabled = osv_debug_enabled(); + if (debug_enabled) { + std::cout << line << std::endl; + } +} + static void seed_openssl() { - debug("Seeding OpenSSL...\n"); + debug_line("Seeding OpenSSL..."); for (;;) { char buf[32]; @@ -39,10 +46,10 @@ static void seed_openssl() // fedora's openssl-1.0.1h-5.fc20 needs 48 bytes instead // of 32, which is what is required by its upstream version // (tag OpenSSL_1_0_1h). In general, we should make no assumptions. - debug("Still not seeded, retrying\n"); + debug_line("Still not seeded, retrying"); } - debug("OpenSSL seeding done.\n"); + debug_line("OpenSSL seeding done."); } void ensure_openssl_initialized() diff --git a/modules/httpserver-api/ssl_server.cc b/modules/httpserver-api/ssl_server.cc index a4f8ada2..a064bd6b 100644 --- a/modules/httpserver-api/ssl_server.cc +++ b/modules/httpserver-api/ssl_server.cc @@ -5,11 +5,12 @@ * BSD license as described in the LICENSE file in the top-level directory. */ -#include <osv/debug.hh> +#include <osv/osv_c_wrappers.h> #include "transport.hh" #include "ssl_server.hh" #include <openssl/ssl.h> +#include <iostream> namespace http { @@ -83,8 +84,10 @@ void ssl_acceptor::do_accept(callback_t callback) [this, socket, callback] (boost::system::error_code ec) { if (ec) { auto remote = socket->lowest_layer().remote_endpoint(); - debug("handshake with " + remote.address().to_string() - + " failed: " + ec.message() + "\n"); + if (osv_debug_enabled()) { + std::cout << "handshake with " << remote.address().to_string() + << " failed: " << ec.message() << std::endl; + } } if (!_tcp_acceptor.is_open()) { diff --git a/modules/httpserver-monitoring-api/Makefile b/modules/httpserver-monitoring-api/Makefile index e26fc06b..8ac415b7 100644 --- a/modules/httpserver-monitoring-api/Makefile +++ b/modules/httpserver-monitoring-api/Makefile @@ -45,7 +45,7 @@ all: $(module_out)/lib$(TARGET).so $(src)/scripts/manifest_from_host.sh $(module_out)/lib$(TARGET).so > usr.manifest; \ fi -$(module_out)/lib$(TARGET).so: $(JSON_OBJ_FILES) $(OBJ_FILES) +$(module_out)/lib$(TARGET).so: $(JSON_OBJ_FILES) $(OBJ_FILES) $(module_out)/options.o $(call quiet, $(CXX) $(CXXFLAGS) $(LDFLAGS) -shared $(STATIC_LIBS) -o $@ $^ $(DYN_LIBS), LINK $@) ifneq ($(MAKECMDGOALS),clean) @@ -64,6 +64,10 @@ $(JSON_OBJ_FILES): $(module_out)/autogen/%.o: autogen/%.cc $(call very-quiet, mkdir -p $(module_out)/autogen) $(call quiet, $(CXX) $(CXXFLAGS) -c -MMD -o $@ $<, CXX $@) +$(module_out)/options.o: $(src)/core/options.cc + $(call very-quiet, mkdir -p $(module_out)) + $(call quiet, $(CXX) $(CXXFLAGS) -c -MMD -o $@ $<, CXX $@) + clean: $(call quiet, $(RM) -f $(TARGET), CLEAN) $(call very-quiet, $(RM) -rf $(module_out)) -- 2.31.1 -- You received this message because you are subscribed to the Google Groups "OSv Development" group. To unsubscribe from this group and stop receiving emails from it, send an email to [email protected]. To view this discussion on the web visit https://groups.google.com/d/msgid/osv-dev/20220117055538.139407-3-jwkozaczuk%40gmail.com.
