]> git.proxmox.com Git - ceph.git/blob - ceph/src/crush/CrushLocation.cc
import quincy beta 17.1.0
[ceph.git] / ceph / src / crush / CrushLocation.cc
1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
3
4 #include <vector>
5
6 #include "CrushLocation.h"
7 #include "CrushWrapper.h"
8 #if defined(WITH_SEASTAR) && !defined(WITH_ALIEN)
9 #include "common/SubProcess.h"
10 #endif
11 #include "common/ceph_context.h"
12 #include "common/config.h"
13 #include "common/debug.h"
14 #include "common/errno.h"
15 #include "include/common_fwd.h"
16 #include "include/compat.h"
17 #include "include/str_list.h"
18
19 namespace TOPNSPC::crush {
20
21 int CrushLocation::update_from_conf()
22 {
23 if (cct->_conf->crush_location.length())
24 return _parse(cct->_conf->crush_location);
25 return 0;
26 }
27
28 int CrushLocation::_parse(const std::string& s)
29 {
30 std::multimap<std::string,std::string> new_crush_location;
31 std::vector<std::string> lvec;
32 get_str_vec(s, ";, \t", lvec);
33 int r = CrushWrapper::parse_loc_multimap(lvec, &new_crush_location);
34 if (r < 0) {
35 lderr(cct) << "warning: crush_location '" << cct->_conf->crush_location
36 << "' does not parse, keeping original crush_location "
37 << loc << dendl;
38 return -EINVAL;
39 }
40 std::lock_guard l(lock);
41 loc.swap(new_crush_location);
42 lgeneric_dout(cct, 10) << "crush_location is " << loc << dendl;
43 return 0;
44 }
45
46 int CrushLocation::update_from_hook()
47 {
48 if (cct->_conf->crush_location_hook.length() == 0)
49 return 0;
50
51 #if defined(WITH_SEASTAR) && !defined(WITH_ALIEN)
52 ceph_abort_msg("crimson does not support crush_location_hook, it must stay empty");
53 #else
54 if (0 != access(cct->_conf->crush_location_hook.c_str(), R_OK)) {
55 lderr(cct) << "the user define crush location hook: " << cct->_conf->crush_location_hook
56 << " may not exist or can not access it" << dendl;
57 return errno;
58 }
59
60 SubProcessTimed hook(
61 cct->_conf->crush_location_hook.c_str(),
62 SubProcess::CLOSE, SubProcess::PIPE, SubProcess::PIPE,
63 cct->_conf->crush_location_hook_timeout);
64 hook.add_cmd_args(
65 "--cluster", cct->_conf->cluster.c_str(),
66 "--id", cct->_conf->name.get_id().c_str(),
67 "--type", cct->_conf->name.get_type_str(),
68 NULL);
69 int ret = hook.spawn();
70 if (ret != 0) {
71 lderr(cct) << "error: failed run " << cct->_conf->crush_location_hook << ": "
72 << hook.err() << dendl;
73 return ret;
74 }
75
76 ceph::buffer::list bl;
77 ret = bl.read_fd(hook.get_stdout(), 100 * 1024);
78 if (ret < 0) {
79 lderr(cct) << "error: failed read stdout from "
80 << cct->_conf->crush_location_hook
81 << ": " << cpp_strerror(-ret) << dendl;
82 ceph::buffer::list err;
83 err.read_fd(hook.get_stderr(), 100 * 1024);
84 lderr(cct) << "stderr:\n";
85 err.hexdump(*_dout);
86 *_dout << dendl;
87 }
88
89 if (hook.join() != 0) {
90 lderr(cct) << "error: failed to join: " << hook.err() << dendl;
91 return -EINVAL;
92 }
93
94 if (ret < 0)
95 return ret;
96
97 std::string out;
98 bl.begin().copy(bl.length(), out);
99 out.erase(out.find_last_not_of(" \n\r\t")+1);
100 return _parse(out);
101 #endif // WITH_SEASTAR && !WITH_ALIEN
102 }
103
104 int CrushLocation::init_on_startup()
105 {
106 if (cct->_conf->crush_location.length()) {
107 return update_from_conf();
108 }
109 if (cct->_conf->crush_location_hook.length()) {
110 return update_from_hook();
111 }
112
113 // start with a sane default
114 char hostname[HOST_NAME_MAX + 1];
115 int r = gethostname(hostname, sizeof(hostname));
116 if (r < 0)
117 strcpy(hostname, "unknown_host");
118 // use short hostname
119 for (unsigned i=0; hostname[i]; ++i) {
120 if (hostname[i] == '.') {
121 hostname[i] = '\0';
122 break;
123 }
124 }
125 std::lock_guard l(lock);
126 loc.clear();
127 loc.insert(std::make_pair<std::string,std::string>("host", hostname));
128 loc.insert(std::make_pair<std::string,std::string>("root", "default"));
129 return 0;
130 }
131
132 std::multimap<std::string,std::string> CrushLocation::get_location() const
133 {
134 std::lock_guard l(lock);
135 return loc;
136 }
137
138 std::ostream& operator<<(std::ostream& os, const CrushLocation& loc)
139 {
140 bool first = true;
141 for (auto& [type, pos] : loc.get_location()) {
142 if (first) {
143 first = false;
144 } else {
145 os << ", ";
146 }
147 os << '"' << type << '=' << pos << '"';
148 }
149 return os;
150 }
151
152 }