]>
git.proxmox.com Git - ceph.git/blob - ceph/src/common/util.cc
1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
4 * Ceph - scalable distributed file system
6 * Copyright (C) 2012 Inktank Storage, Inc.
8 * This is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License version 2.1, as published by the Free Software
11 * Foundation. See file COPYING.
15 #include <sys/utsname.h>
16 #include <boost/lexical_cast.hpp>
18 #include "include/compat.h"
19 #include "include/util.h"
20 #include "common/debug.h"
21 #include "common/errno.h"
22 #include "common/version.h"
28 #if defined(__APPLE__) || defined(__FreeBSD__)
29 #include <sys/param.h>
30 #include <sys/mount.h>
31 #if defined(__APPLE__)
32 #include <sys/types.h>
33 #include <sys/sysctl.h>
41 int get_fs_stats(ceph_data_stats_t
&stats
, const char *path
)
47 int err
= ::statfs(path
, &stbuf
);
52 stats
.byte_total
= stbuf
.f_blocks
* stbuf
.f_bsize
;
53 stats
.byte_used
= (stbuf
.f_blocks
- stbuf
.f_bfree
) * stbuf
.f_bsize
;
54 stats
.byte_avail
= stbuf
.f_bavail
* stbuf
.f_bsize
;
55 stats
.avail_percent
= (((float)stats
.byte_avail
/stats
.byte_total
)*100);
59 static char* value_sanitize(char *value
)
61 while (isspace(*value
) || *value
== '"')
64 char* end
= value
+ strlen(value
) - 1;
65 while (end
> value
&& (isspace(*end
) || *end
== '"'))
73 static bool value_set(char *buf
, const char *prefix
,
74 map
<string
, string
> *pm
, const char *key
)
76 if (strncmp(buf
, prefix
, strlen(prefix
))) {
80 (*pm
)[key
] = value_sanitize(buf
+ strlen(prefix
));
84 static void file_values_parse(const map
<string
, string
>& kvm
, FILE *fp
, map
<string
, string
> *m
, CephContext
*cct
) {
86 while (fgets(buf
, sizeof(buf
) - 1, fp
) != NULL
) {
87 for (auto& kv
: kvm
) {
88 if (value_set(buf
, kv
.second
.c_str(), m
, kv
.first
.c_str()))
94 static bool os_release_parse(map
<string
, string
> *m
, CephContext
*cct
)
96 #if defined(__linux__)
97 static const map
<string
, string
> kvm
= {
99 { "distro_description", "PRETTY_NAME=" },
100 { "distro_version", "VERSION_ID=" }
103 FILE *fp
= fopen("/etc/os-release", "r");
106 lderr(cct
) << "os_release_parse - failed to open /etc/os-release: " << cpp_strerror(ret
) << dendl
;
110 file_values_parse(kvm
, fp
, m
, cct
);
113 #elif defined(__FreeBSD__)
117 m
->insert(std::make_pair("distro", u
.sysname
));
118 m
->insert(std::make_pair("distro_description", u
.version
));
119 m
->insert(std::make_pair("distro_version", u
.release
));
126 static void distro_detect(map
<string
, string
> *m
, CephContext
*cct
)
128 if (!os_release_parse(m
, cct
)) {
129 lderr(cct
) << "distro_detect - /etc/os-release is required" << dendl
;
132 for (const char* rk
: {"distro", "distro_description"}) {
133 if (m
->find(rk
) == m
->end())
134 lderr(cct
) << "distro_detect - can't detect " << rk
<< dendl
;
138 int get_cgroup_memory_limit(uint64_t *limit
)
140 // /sys/fs/cgroup/memory/memory.limit_in_bytes
142 // the magic value 9223372036854771712 or 0x7ffffffffffff000
143 // appears to mean no limit.
144 FILE *f
= fopen(PROCPREFIX
"/sys/fs/cgroup/memory/memory.limit_in_bytes", "r");
151 char *line
= fgets(buf
, sizeof(buf
), f
);
156 if (sscanf(line
, "%lld", &value
) != 1) {
159 if (value
== 0x7ffffffffffff000) {
160 *limit
= 0; // no limit
170 void collect_sys_info(map
<string
, string
> *m
, CephContext
*cct
)
173 (*m
)["ceph_version"] = pretty_version_to_str();
174 (*m
)["ceph_version_short"] = ceph_version_to_str();
175 (*m
)["ceph_release"] = ceph_release_to_str();
181 (*m
)["os"] = u
.sysname
;
182 (*m
)["kernel_version"] = u
.release
;
183 (*m
)["kernel_description"] = u
.version
;
184 (*m
)["hostname"] = u
.nodename
;
185 (*m
)["arch"] = u
.machine
;
188 // but wait, am i in a container?
189 bool in_container
= false;
191 if (const char *pod_name
= getenv("POD_NAME")) {
192 (*m
)["pod_name"] = pod_name
;
195 if (const char *container_name
= getenv("CONTAINER_NAME")) {
196 (*m
)["container_name"] = container_name
;
199 if (const char *container_image
= getenv("CONTAINER_IMAGE")) {
200 (*m
)["container_image"] = container_image
;
204 if (const char *node_name
= getenv("NODE_NAME")) {
205 (*m
)["container_hostname"] = u
.nodename
;
206 (*m
)["hostname"] = node_name
;
208 if (const char *ns
= getenv("POD_NAMESPACE")) {
209 (*m
)["pod_namespace"] = ns
;
217 size_t len
= sizeof(size
);
218 r
= sysctlbyname("hw.memsize", &size
, &len
, NULL
, 0);
220 (*m
)["mem_total_kb"] = std::to_string(size
);
225 size_t len
= sizeof(vmusage
);
226 r
= sysctlbyname("vm.swapusage", &vmusage
, &len
, NULL
, 0);
228 (*m
)["mem_swap_kb"] = std::to_string(vmusage
.xsu_total
);
234 size_t len
= sizeof(buf
);
235 r
= sysctlbyname("machdep.cpu.brand_string", buf
, &len
, NULL
, 0);
243 FILE *f
= fopen(PROCPREFIX
"/proc/meminfo", "r");
247 char *line
= fgets(buf
, sizeof(buf
), f
);
252 int r
= sscanf(line
, "%s %lld", key
, &value
);
254 if (strcmp(key
, "MemTotal:") == 0)
255 (*m
)["mem_total_kb"] = boost::lexical_cast
<string
>(value
);
256 else if (strcmp(key
, "SwapTotal:") == 0)
257 (*m
)["mem_swap_kb"] = boost::lexical_cast
<string
>(value
);
262 uint64_t cgroup_limit
;
263 if (get_cgroup_memory_limit(&cgroup_limit
) == 0 &&
265 (*m
)["mem_cgroup_limit"] = boost::lexical_cast
<string
>(cgroup_limit
);
269 f
= fopen(PROCPREFIX
"/proc/cpuinfo", "r");
273 char *line
= fgets(buf
, sizeof(buf
), f
);
276 if (strncmp(line
, "model name", 10) == 0) {
277 char *c
= strchr(buf
, ':');
293 distro_detect(m
, cct
);
296 void dump_services(Formatter
* f
, const map
<string
, list
<int> >& services
, const char* type
)
300 f
->open_object_section(type
);
301 for (map
<string
, list
<int> >::const_iterator host
= services
.begin();
302 host
!= services
.end(); ++host
) {
303 f
->open_array_section(host
->first
.c_str());
304 const list
<int>& hosted
= host
->second
;
305 for (list
<int>::const_iterator s
= hosted
.begin();
306 s
!= hosted
.end(); ++s
) {
307 f
->dump_int(type
, *s
);
314 void dump_services(Formatter
* f
, const map
<string
, list
<string
> >& services
, const char* type
)
318 f
->open_object_section(type
);
319 for (const auto& host
: services
) {
320 f
->open_array_section(host
.first
.c_str());
321 const auto& hosted
= host
.second
;
322 for (const auto& s
: hosted
) {
323 f
->dump_string(type
, s
);
330 // If non-printable characters found then convert bufferlist to
331 // base64 encoded string indicating whether it did.
332 string
cleanbin(bufferlist
&bl
, bool &base64
)
334 bufferlist::iterator it
;
335 for (it
= bl
.begin(); it
!= bl
.end(); ++it
) {
339 if (it
== bl
.end()) {
341 string
result(bl
.c_str(), bl
.length());
346 bl
.encode_base64(b64
);
347 string
encoded(b64
.c_str(), b64
.length());
352 // If non-printable characters found then convert to "Base64:" followed by
354 string
cleanbin(string
&str
)
359 string result
= cleanbin(bl
, base64
);
361 result
= "Base64:" + result
;
365 std::string
bytes2str(uint64_t count
) {
366 static char s
[][2] = {"\0", "k", "M", "G", "T", "P", "E", "\0"};
368 while (count
>= 1024 && *s
[i
+1]) {
373 snprintf(str
, sizeof str
, "%" PRIu64
"%sB", count
, s
[i
]);
374 return std::string(str
);