*
*/
-#include <errno.h>
#include <sys/utsname.h>
-#include <boost/lexical_cast.hpp>
+#include <fstream>
+#include <boost/algorithm/string.hpp>
#include "include/compat.h"
#include "include/util.h"
#include "common/debug.h"
#include "common/errno.h"
-#include "common/strtol.h"
#include "common/version.h"
#ifdef HAVE_SYS_VFS_H
#include <sys/vfs.h>
#endif
-#if defined(DARWIN) || defined(__FreeBSD__)
+#if defined(__APPLE__) || defined(__FreeBSD__)
#include <sys/param.h>
#include <sys/mount.h>
+#if defined(__APPLE__)
+#include <sys/types.h>
+#include <sys/sysctl.h>
+#endif
#endif
-int64_t unit_to_bytesize(string val, ostream *pss)
-{
- if (val.empty()) {
- if (pss)
- *pss << "value is empty!";
- return -EINVAL;
- }
-
- char c = val[val.length()-1];
- int modifier = 0;
- if (!::isdigit(c)) {
- if (val.length() < 2) {
- if (pss)
- *pss << "invalid value: " << val;
- return -EINVAL;
- }
- val = val.substr(0,val.length()-1);
- switch (c) {
- case 'B':
- break;
- case 'k':
- case 'K':
- modifier = 10;
- break;
- case 'M':
- modifier = 20;
- break;
- case 'G':
- modifier = 30;
- break;
- case 'T':
- modifier = 40;
- break;
- case 'P':
- modifier = 50;
- break;
- case 'E':
- modifier = 60;
- break;
- default:
- if (pss)
- *pss << "unrecognized modifier '" << c << "'" << std::endl;
- return -EINVAL;
- }
- }
+#include <string>
- if (val[0] == '+' || val[0] == '-') {
- if (pss)
- *pss << "expected numerical value, got: " << val;
- return -EINVAL;
- }
-
- string err;
- int64_t r = strict_strtoll(val.c_str(), 10, &err);
- if ((r == 0) && !err.empty()) {
- if (pss)
- *pss << err;
- return -1;
- }
- if (r < 0) {
- if (pss)
- *pss << "unable to parse positive integer '" << val << "'";
- return -1;
- }
- return (r * (1LL << modifier));
-}
+#include <stdio.h>
int get_fs_stats(ceph_data_stats_t &stats, const char *path)
{
static bool os_release_parse(map<string, string> *m, CephContext *cct)
{
+#if defined(__linux__)
static const map<string, string> kvm = {
{ "distro", "ID=" },
{ "distro_description", "PRETTY_NAME=" },
file_values_parse(kvm, fp, m, cct);
fclose(fp);
+#elif defined(__FreeBSD__)
+ struct utsname u;
+ int r = uname(&u);
+ if (!r) {
+ m->insert(std::make_pair("distro", u.sysname));
+ m->insert(std::make_pair("distro_description", u.version));
+ m->insert(std::make_pair("distro_version", u.release));
+ }
+#endif
return true;
}
lderr(cct) << "distro_detect - /etc/os-release is required" << dendl;
}
- for (const char* rk: {"distro", "distro_version"}) {
+ for (const char* rk: {"distro", "distro_description"}) {
if (m->find(rk) == m->end())
lderr(cct) << "distro_detect - can't detect " << rk << dendl;
}
}
+int get_cgroup_memory_limit(uint64_t *limit)
+{
+ // /sys/fs/cgroup/memory/memory.limit_in_bytes
+
+ // the magic value 9223372036854771712 or 0x7ffffffffffff000
+ // appears to mean no limit.
+ FILE *f = fopen(PROCPREFIX "/sys/fs/cgroup/memory/memory.limit_in_bytes", "r");
+ if (!f) {
+ return -errno;
+ }
+ char buf[100];
+ int ret = 0;
+ long long value;
+ char *line = fgets(buf, sizeof(buf), f);
+ if (!line) {
+ ret = -EINVAL;
+ goto out;
+ }
+ if (sscanf(line, "%lld", &value) != 1) {
+ ret = -EINVAL;
+ }
+ if (value == 0x7ffffffffffff000) {
+ *limit = 0; // no limit
+ } else {
+ *limit = value;
+ }
+out:
+ fclose(f);
+ return ret;
+}
+
+
void collect_sys_info(map<string, string> *m, CephContext *cct)
{
// version
(*m)["ceph_version"] = pretty_version_to_str();
+ (*m)["ceph_version_short"] = ceph_version_to_str();
+ (*m)["ceph_release"] = ceph_release_to_str();
// kernel info
struct utsname u;
(*m)["arch"] = u.machine;
}
+ // but wait, am i in a container?
+ bool in_container = false;
+
+ if (const char *pod_name = getenv("POD_NAME")) {
+ (*m)["pod_name"] = pod_name;
+ in_container = true;
+ }
+ if (const char *container_name = getenv("CONTAINER_NAME")) {
+ (*m)["container_name"] = container_name;
+ in_container = true;
+ }
+ if (const char *container_image = getenv("CONTAINER_IMAGE")) {
+ (*m)["container_image"] = container_image;
+ in_container = true;
+ }
+ if (in_container) {
+ if (const char *node_name = getenv("NODE_NAME")) {
+ (*m)["container_hostname"] = u.nodename;
+ (*m)["hostname"] = node_name;
+ }
+ if (const char *ns = getenv("POD_NAMESPACE")) {
+ (*m)["pod_namespace"] = ns;
+ }
+ }
+
+#ifdef __APPLE__
// memory
- FILE *f = fopen(PROCPREFIX "/proc/meminfo", "r");
- if (f) {
+ {
+ uint64_t size;
+ size_t len = sizeof(size);
+ r = sysctlbyname("hw.memsize", &size, &len, NULL, 0);
+ if (r == 0) {
+ (*m)["mem_total_kb"] = std::to_string(size);
+ }
+ }
+ {
+ xsw_usage vmusage;
+ size_t len = sizeof(vmusage);
+ r = sysctlbyname("vm.swapusage", &vmusage, &len, NULL, 0);
+ if (r == 0) {
+ (*m)["mem_swap_kb"] = std::to_string(vmusage.xsu_total);
+ }
+ }
+ // processor
+ {
char buf[100];
- while (!feof(f)) {
- char *line = fgets(buf, sizeof(buf), f);
- if (!line)
- break;
- char key[40];
- long long value;
- int r = sscanf(line, "%s %lld", key, &value);
- if (r == 2) {
- if (strcmp(key, "MemTotal:") == 0)
- (*m)["mem_total_kb"] = boost::lexical_cast<string>(value);
- else if (strcmp(key, "SwapTotal:") == 0)
- (*m)["mem_swap_kb"] = boost::lexical_cast<string>(value);
+ size_t len = sizeof(buf);
+ r = sysctlbyname("machdep.cpu.brand_string", buf, &len, NULL, 0);
+ if (r == 0) {
+ buf[len - 1] = '\0';
+ (*m)["cpu"] = buf;
+ }
+ }
+#else
+ // memory
+ if (std::ifstream f{PROCPREFIX "/proc/meminfo"}; !f.fail()) {
+ for (std::string line; std::getline(f, line); ) {
+ std::vector<string> parts;
+ boost::split(parts, line, boost::is_any_of(":\t "), boost::token_compress_on);
+ if (parts.size() != 3) {
+ continue;
+ }
+ if (parts[0] == "MemTotal") {
+ (*m)["mem_total_kb"] = parts[1];
+ } else if (parts[0] == "SwapTotal") {
+ (*m)["mem_swap_kb"] = parts[1];
}
}
- fclose(f);
+ }
+ uint64_t cgroup_limit;
+ if (get_cgroup_memory_limit(&cgroup_limit) == 0 &&
+ cgroup_limit > 0) {
+ (*m)["mem_cgroup_limit"] = std::to_string(cgroup_limit);
}
// processor
- f = fopen(PROCPREFIX "/proc/cpuinfo", "r");
- if (f) {
- char buf[100];
- while (!feof(f)) {
- char *line = fgets(buf, sizeof(buf), f);
- if (!line)
- break;
- if (strncmp(line, "model name", 10) == 0) {
- char *c = strchr(buf, ':');
- c++;
- while (*c == ' ')
- ++c;
- char *nl = c;
- while (*nl != '\n')
- ++nl;
- *nl = '\0';
- (*m)["cpu"] = c;
+ if (std::ifstream f{PROCPREFIX "/proc/cpuinfo"}; !f.fail()) {
+ for (std::string line; std::getline(f, line); ) {
+ std::vector<string> parts;
+ boost::split(parts, line, boost::is_any_of(":"));
+ if (parts.size() != 2) {
+ continue;
+ }
+ boost::trim(parts[0]);
+ boost::trim(parts[1]);
+ if (parts[0] == "model name") {
+ (*m)["cpu"] = parts[1];
break;
}
}
- fclose(f);
}
-
+#endif
// distro info
distro_detect(m, cct);
}
void dump_services(Formatter* f, const map<string, list<int> >& services, const char* type)
{
- assert(f);
+ ceph_assert(f);
f->open_object_section(type);
for (map<string, list<int> >::const_iterator host = services.begin();
f->close_section();
}
+void dump_services(Formatter* f, const map<string, list<string> >& services, const char* type)
+{
+ ceph_assert(f);
+
+ f->open_object_section(type);
+ for (const auto& host : services) {
+ f->open_array_section(host.first.c_str());
+ const auto& hosted = host.second;
+ for (const auto& s : hosted) {
+ f->dump_string(type, s);
+ }
+ f->close_section();
+ }
+ f->close_section();
+}
// If non-printable characters found then convert bufferlist to
// base64 encoded string indicating whether it did.
-string cleanbin(bufferlist &bl, bool &base64)
+string cleanbin(bufferlist &bl, bool &base64, bool show)
{
bufferlist::iterator it;
for (it = bl.begin(); it != bl.end(); ++it) {
bufferlist b64;
bl.encode_base64(b64);
string encoded(b64.c_str(), b64.length());
+ if (show)
+ encoded = "Base64:" + encoded;
base64 = true;
return encoded;
}
bool base64;
bufferlist bl;
bl.append(str);
- string result = cleanbin(bl, base64);
- if (base64)
- result = "Base64:" + result;
+ string result = cleanbin(bl, base64, true);
return result;
}
+
+std::string bytes2str(uint64_t count) {
+ static char s[][2] = {"\0", "k", "M", "G", "T", "P", "E", "\0"};
+ int i = 0;
+ while (count >= 1024 && *s[i+1]) {
+ count >>= 10;
+ i++;
+ }
+ char str[128];
+ snprintf(str, sizeof str, "%" PRIu64 "%sB", count, s[i]);
+ return std::string(str);
+}