X-Git-Url: https://gerrit.opnfv.org/gerrit/gitweb?a=blobdiff_plain;f=src%2Fceph%2Fsrc%2Fcommon%2Futil.cc;fp=src%2Fceph%2Fsrc%2Fcommon%2Futil.cc;h=4f31b932faa4385127036f7180cb6ef2a5197882;hb=812ff6ca9fcd3e629e49d4328905f33eee8ca3f5;hp=0000000000000000000000000000000000000000;hpb=15280273faafb77777eab341909a3f495cf248d9;p=stor4nfv.git diff --git a/src/ceph/src/common/util.cc b/src/ceph/src/common/util.cc new file mode 100644 index 0000000..4f31b93 --- /dev/null +++ b/src/ceph/src/common/util.cc @@ -0,0 +1,320 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab +/* + * Ceph - scalable distributed file system + * + * Copyright (C) 2012 Inktank Storage, Inc. + * + * This is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software + * Foundation. See file COPYING. + * + */ + +#include +#include + +#include "include/compat.h" +#include "include/util.h" +#include "common/debug.h" +#include "common/errno.h" +#include "common/version.h" + +#ifdef HAVE_SYS_VFS_H +#include +#endif + +#if defined(DARWIN) || defined(__FreeBSD__) +#include +#include +#endif + +#include + +#include + +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; + } + } + + 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)); +} + +int get_fs_stats(ceph_data_stats_t &stats, const char *path) +{ + if (!path) + return -EINVAL; + + struct statfs stbuf; + int err = ::statfs(path, &stbuf); + if (err < 0) { + return -errno; + } + + stats.byte_total = stbuf.f_blocks * stbuf.f_bsize; + stats.byte_used = (stbuf.f_blocks - stbuf.f_bfree) * stbuf.f_bsize; + stats.byte_avail = stbuf.f_bavail * stbuf.f_bsize; + stats.avail_percent = (((float)stats.byte_avail/stats.byte_total)*100); + return 0; +} + +static char* value_sanitize(char *value) +{ + while (isspace(*value) || *value == '"') + value++; + + char* end = value + strlen(value) - 1; + while (end > value && (isspace(*end) || *end == '"')) + end--; + + *(end + 1) = '\0'; + + return value; +} + +static bool value_set(char *buf, const char *prefix, + map *pm, const char *key) +{ + if (strncmp(buf, prefix, strlen(prefix))) { + return false; + } + + (*pm)[key] = value_sanitize(buf + strlen(prefix)); + return true; +} + +static void file_values_parse(const map& kvm, FILE *fp, map *m, CephContext *cct) { + char buf[512]; + while (fgets(buf, sizeof(buf) - 1, fp) != NULL) { + for (auto& kv : kvm) { + if (value_set(buf, kv.second.c_str(), m, kv.first.c_str())) + continue; + } + } +} + +static bool os_release_parse(map *m, CephContext *cct) +{ + static const map kvm = { + { "distro", "ID=" }, + { "distro_description", "PRETTY_NAME=" }, + { "distro_version", "VERSION_ID=" } + }; + + FILE *fp = fopen("/etc/os-release", "r"); + if (!fp) { + int ret = -errno; + lderr(cct) << "os_release_parse - failed to open /etc/os-release: " << cpp_strerror(ret) << dendl; + return false; + } + + file_values_parse(kvm, fp, m, cct); + + fclose(fp); + + return true; +} + +static void distro_detect(map *m, CephContext *cct) +{ + if (!os_release_parse(m, cct)) { + lderr(cct) << "distro_detect - /etc/os-release is required" << dendl; + } + + for (const char* rk: {"distro", "distro_version"}) { + if (m->find(rk) == m->end()) + lderr(cct) << "distro_detect - can't detect " << rk << dendl; + } +} + +void collect_sys_info(map *m, CephContext *cct) +{ + // version + (*m)["ceph_version"] = pretty_version_to_str(); + + // kernel info + struct utsname u; + int r = uname(&u); + if (r >= 0) { + (*m)["os"] = u.sysname; + (*m)["kernel_version"] = u.release; + (*m)["kernel_description"] = u.version; + (*m)["hostname"] = u.nodename; + (*m)["arch"] = u.machine; + } + + // memory + FILE *f = fopen(PROCPREFIX "/proc/meminfo", "r"); + if (f) { + 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(value); + else if (strcmp(key, "SwapTotal:") == 0) + (*m)["mem_swap_kb"] = boost::lexical_cast(value); + } + } + fclose(f); + } + + // 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; + break; + } + } + fclose(f); + } + + // distro info + distro_detect(m, cct); +} + +void dump_services(Formatter* f, const map >& services, const char* type) +{ + assert(f); + + f->open_object_section(type); + for (map >::const_iterator host = services.begin(); + host != services.end(); ++host) { + f->open_array_section(host->first.c_str()); + const list& hosted = host->second; + for (list::const_iterator s = hosted.begin(); + s != hosted.end(); ++s) { + f->dump_int(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) +{ + bufferlist::iterator it; + for (it = bl.begin(); it != bl.end(); ++it) { + if (iscntrl(*it)) + break; + } + if (it == bl.end()) { + base64 = false; + string result(bl.c_str(), bl.length()); + return result; + } + + bufferlist b64; + bl.encode_base64(b64); + string encoded(b64.c_str(), b64.length()); + base64 = true; + return encoded; +} + +// If non-printable characters found then convert to "Base64:" followed by +// base64 encoding +string cleanbin(string &str) +{ + bool base64; + bufferlist bl; + bl.append(str); + string result = cleanbin(bl, base64); + if (base64) + result = "Base64:" + result; + 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); +}