]> git.proxmox.com Git - ceph.git/blob - ceph/src/crimson/crush/CrushLocation.cc
update ceph source to reef 18.1.2
[ceph.git] / ceph / src / crimson / 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 #include "CrushLocation.h"
4
5 #include <vector>
6 #include <boost/algorithm/string/trim.hpp>
7 #include <seastar/util/process.hh>
8 #include <seastar/util/later.hh>
9
10 #include "crush/CrushWrapper.h"
11 #include "crimson/common/log.h"
12 #include "crimson/common/config_proxy.h"
13
14 static seastar::logger& logger() {
15 return crimson::get_logger(ceph_subsys_crush);
16 }
17
18 using namespace crimson::common;
19
20 namespace crimson::crush {
21
22 seastar::future<> CrushLocation::update_from_conf()
23 {
24 auto crush_location = local_conf().get_val<std::string>("crush_location");
25 if (crush_location.length()) {
26 _parse(crush_location);
27 }
28
29 return seastar::now();
30 }
31
32 void CrushLocation::_parse(const std::string& s)
33 {
34 std::multimap<std::string, std::string> new_crush_location;
35 std::vector<std::string> lvec;
36 get_str_vec(s, ";, \t", lvec);
37 int r = CrushWrapper::parse_loc_multimap(lvec, &new_crush_location);
38 if (r < 0) {
39 logger().error("CrushWrapper::parse_loc_multimap error, keeping original\
40 crush_location {}", *this);
41 return;
42 }
43
44 loc.swap(new_crush_location);
45 logger().info("{}: crush_location is {}", __func__, *this);
46 return;
47 }
48
49 seastar::future<> CrushLocation::update_from_hook()
50 {
51 auto crush_location_hook = local_conf().get_val<std::string>("crush_location_hook");
52 if (crush_location_hook.length() == 0)
53 return seastar::now();
54
55 return seastar::file_exists(
56 crush_location_hook
57 ).then([this] (bool result) {
58 if (!result) {
59 std::stringstream errmsg;
60 errmsg << "the user define crush location hook: "
61 << local_conf().get_val<std::string>("crush_location_hook")
62 << " is not exists.";
63 logger().error("{}", errmsg.str());
64 throw std::runtime_error(errmsg.str());
65 }
66
67 return seastar::file_accessible(
68 local_conf().get_val<std::string>("crush_location_hook"),
69 seastar::access_flags::execute
70 ).then([this] (bool result) {
71 if (!result) {
72 std::stringstream errmsg;
73 errmsg << "the user define crush location hook: "
74 << local_conf().get_val<std::string>("crush_location_hook")
75 << " is not executable.";
76 logger().error("{}", errmsg.str());
77 throw std::runtime_error(errmsg.str());
78 }
79
80 seastar::experimental::spawn_parameters params = {
81 .argv = {
82 local_conf().get_val<std::string>("crush_location_hook"),
83 "--cluster",
84 local_conf()->cluster,
85 "--id",
86 local_conf()->name.get_id(),
87 "--type",
88 local_conf()->name.get_type_str()
89 }
90 };
91 return seastar::experimental::spawn_process(
92 local_conf().get_val<std::string>("crush_location_hook"),
93 std::move(params)
94 ).then([this] (auto process) {
95 auto stdout = process.stdout();
96 return do_with(
97 std::move(process),
98 std::move(stdout),
99 [this](auto& process, auto& stdout)
100 {
101 return stdout.read().then([] (seastar::temporary_buffer<char> buf) {
102 auto out = std::string(buf.get(), buf.size());
103 boost::algorithm::trim_if(out, boost::algorithm::is_any_of(" \n\r\t"));
104 return seastar::make_ready_future<std::string>(std::move(out));
105 }).then([&process, this] (auto out) {
106 return process.wait(
107 ).then([out = std::move(out), this] (auto wstatus) {
108 auto* exit_signal = std::get_if<seastar::experimental::process::wait_signaled>(&wstatus);
109 if (exit_signal != nullptr) {
110 std::stringstream errmsg;
111 errmsg << "the user define crush location hook: "
112 << local_conf().get_val<std::string>("crush_location_hook")
113 << " terminated, terminated signal is "
114 << exit_signal->terminating_signal;
115 logger().error("{}", errmsg.str());
116 throw std::runtime_error(errmsg.str());
117 }
118
119 auto* exit_status = std::get_if<seastar::experimental::process::wait_exited>(&wstatus);
120 if (exit_status->exit_code != 0) {
121 std::stringstream errmsg;
122 errmsg << "the user define crush location hook: "
123 << local_conf().get_val<std::string>("crush_location_hook")
124 << " execute failed, exit_code is " << exit_status->exit_code;
125 logger().error("{}", errmsg.str());
126 throw std::runtime_error(errmsg.str());
127 } else {
128 _parse(out);
129 }
130 return seastar::now();
131 });
132 });
133 });
134 });
135 });
136 });
137 }
138
139 seastar::future<> CrushLocation::init_on_startup()
140 {
141 if (local_conf().get_val<std::string>("crush_location").length()) {
142 return update_from_conf();
143 }
144 if (local_conf().get_val<std::string>("crush_location_hook").length()) {
145 return update_from_hook();
146 }
147
148 // start with a sane default
149 char hostname[HOST_NAME_MAX + 1];
150 int r = gethostname(hostname, sizeof(hostname));
151 if (r < 0)
152 strcpy(hostname, "unknown_host");
153 // use short hostname
154 for (unsigned i=0; hostname[i]; ++i) {
155 if (hostname[i] == '.') {
156 hostname[i] = '\0';
157 break;
158 }
159 }
160
161 loc.clear();
162 loc.insert(std::make_pair<std::string, std::string>("host", hostname));
163 loc.insert(std::make_pair<std::string, std::string>("root", "default"));
164 return seastar::now();
165 }
166
167 std::multimap<std::string,std::string> CrushLocation::get_location() const
168 {
169 return loc;
170 }
171
172 std::ostream& operator<<(std::ostream& os, const CrushLocation& loc)
173 {
174 bool first = true;
175 for (auto& [type, pos] : loc.get_location()) {
176 if (first) {
177 first = false;
178 } else {
179 os << ", ";
180 }
181 os << '"' << type << '=' << pos << '"';
182 }
183 return os;
184 }
185
186 }