]> git.proxmox.com Git - ceph.git/blame - ceph/src/osd/OSDCap.cc
update download target update for octopus release
[ceph.git] / ceph / src / osd / OSDCap.cc
CommitLineData
7c673cae
FG
1// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2// vim: ts=8 sw=2 smarttab
3/*
4 * Ceph - scalable distributed file system
5 *
6 * Copyright (C) 2009-2011 New Dream Network
7 *
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.
12 *
13 */
14
15#include <boost/config/warning_disable.hpp>
16#include <boost/spirit/include/qi.hpp>
17#include <boost/spirit/include/phoenix_operator.hpp>
18#include <boost/spirit/include/phoenix.hpp>
11fdf7f2 19#include <boost/algorithm/string/predicate.hpp>
7c673cae
FG
20
21#include "OSDCap.h"
22#include "common/config.h"
23#include "common/debug.h"
11fdf7f2 24#include "include/ipaddr.h"
7c673cae
FG
25
26using std::ostream;
27using std::vector;
28
31f18b77 29ostream& operator<<(ostream& out, const osd_rwxa_t& p)
c07f9fc5 30{
7c673cae
FG
31 if (p == OSD_CAP_ANY)
32 return out << "*";
33
34 if (p & OSD_CAP_R)
35 out << "r";
36 if (p & OSD_CAP_W)
37 out << "w";
38 if ((p & OSD_CAP_X) == OSD_CAP_X) {
39 out << "x";
40 } else {
41 if (p & OSD_CAP_CLS_R)
42 out << " class-read";
43 if (p & OSD_CAP_CLS_W)
44 out << " class-write";
45 }
46 return out;
47}
48
49ostream& operator<<(ostream& out, const OSDCapSpec& s)
50{
51 if (s.allow)
52 return out << s.allow;
11fdf7f2
TL
53 if (s.class_name.length()) {
54 out << "class '" << s.class_name << "'";
55 if (!s.method_name.empty()) {
56 out << " '" << s.method_name << "'";
57 }
58 }
7c673cae
FG
59 return out;
60}
61
c07f9fc5
FG
62ostream& operator<<(ostream& out, const OSDCapPoolNamespace& pns)
63{
64 if (!pns.pool_name.empty()) {
65 out << "pool " << pns.pool_name << " ";
66 }
67 if (pns.nspace) {
68 out << "namespace ";
69 if (pns.nspace->empty()) {
70 out << "\"\"";
71 } else {
72 out << *pns.nspace;
73 }
74 out << " ";
75 }
76 return out;
77}
78
11fdf7f2
TL
79ostream& operator<<(ostream &out, const OSDCapPoolTag &pt)
80{
81 out << "app " << pt.application << " key " << pt.key << " val " << pt.value
82 << " ";
83 return out;
84}
85
7c673cae
FG
86ostream& operator<<(ostream& out, const OSDCapMatch& m)
87{
11fdf7f2 88 if (!m.pool_namespace.pool_name.empty() || m.pool_namespace.nspace) {
c07f9fc5 89 out << m.pool_namespace;
7c673cae 90 }
c07f9fc5 91
11fdf7f2
TL
92 if (!m.pool_tag.application.empty()) {
93 out << m.pool_tag;
94 }
95
7c673cae
FG
96 if (m.object_prefix.length()) {
97 out << "object_prefix " << m.object_prefix << " ";
98 }
7c673cae
FG
99 return out;
100}
101
c07f9fc5 102ostream& operator<<(ostream& out, const OSDCapProfile& m)
7c673cae 103{
c07f9fc5
FG
104 out << "profile " << m.name;
105 out << m.pool_namespace;
106 return out;
107}
108
109bool OSDCapPoolNamespace::is_match(const std::string& pn,
110 const std::string& ns) const
111{
112 if (!pool_name.empty()) {
113 if (pool_name != pn) {
7c673cae 114 return false;
c07f9fc5 115 }
7c673cae 116 }
c07f9fc5 117 if (nspace) {
eafe8130 118 if (!nspace->empty() && nspace->back() == '*' &&
11fdf7f2
TL
119 boost::starts_with(ns, nspace->substr(0, nspace->length() - 1))) {
120 return true;
121 }
122
c07f9fc5 123 if (*nspace != ns) {
7c673cae 124 return false;
c07f9fc5 125 }
7c673cae 126 }
c07f9fc5
FG
127 return true;
128}
129
130bool OSDCapPoolNamespace::is_match_all() const
131{
132 if (!pool_name.empty())
133 return false;
134 if (nspace)
135 return false;
136 return true;
137}
138
11fdf7f2
TL
139bool OSDCapPoolTag::is_match(const app_map_t& app_map) const
140{
141 if (application.empty()) {
142 return true;
143 }
144 auto kv_map = app_map.find(application);
145 if (kv_map == app_map.end()) {
146 return false;
147 }
148 if (!key.compare("*") && !value.compare("*")) {
149 return true;
150 }
151 if (!key.compare("*")) {
152 for (auto it : kv_map->second) {
153 if (it.second == value) {
154 return true;
155 }
156 }
157 return false;
158 }
159 auto kv_val = kv_map->second.find(key);
160 if (kv_val == kv_map->second.end()) {
161 return false;
162 }
163 if (!value.compare("*")) {
164 return true;
165 }
166 return kv_val->second == value;
167}
168
169bool OSDCapPoolTag::is_match_all() const {
170 return application.empty();
171}
172
c07f9fc5 173bool OSDCapMatch::is_match(const string& pn, const string& ns,
11fdf7f2
TL
174 const OSDCapPoolTag::app_map_t& app_map,
175 const string& object) const
c07f9fc5 176{
11fdf7f2
TL
177 if (!pool_namespace.is_match(pn, ns)) {
178 return false;
179 } else if (!pool_tag.is_match(app_map)) {
c07f9fc5 180 return false;
7c673cae 181 }
c07f9fc5 182
7c673cae
FG
183 if (object_prefix.length()) {
184 if (object.find(object_prefix) != 0)
185 return false;
186 }
187 return true;
188}
189
190bool OSDCapMatch::is_match_all() const
191{
11fdf7f2 192if (!pool_namespace.is_match_all()) {
7c673cae 193 return false;
11fdf7f2 194 } else if (!pool_tag.is_match_all()) {
7c673cae 195 return false;
c07f9fc5
FG
196 }
197
198 if (object_prefix.length()) {
7c673cae 199 return false;
c07f9fc5 200 }
7c673cae
FG
201 return true;
202}
203
204ostream& operator<<(ostream& out, const OSDCapGrant& g)
205{
c07f9fc5
FG
206 out << "grant(";
207 if (g.profile.is_valid()) {
208 out << g.profile << " [";
209 for (auto it = g.profile_grants.cbegin();
210 it != g.profile_grants.cend(); ++it) {
211 if (it != g.profile_grants.cbegin()) {
212 out << ",";
213 }
214 out << *it;
215 }
216 out << "]";
217 } else {
218 out << g.match << g.spec;
219 }
11fdf7f2
TL
220 if (g.network.size()) {
221 out << " network " << g.network;
222 }
c07f9fc5
FG
223 out << ")";
224 return out;
7c673cae
FG
225}
226
11fdf7f2
TL
227void OSDCapGrant::set_network(const string& n)
228{
229 network = n;
230 network_valid = ::parse_network(n.c_str(), &network_parsed, &network_prefix);
231}
232
c07f9fc5 233bool OSDCapGrant::allow_all() const
7c673cae 234{
c07f9fc5
FG
235 if (profile.is_valid()) {
236 return std::any_of(profile_grants.cbegin(), profile_grants.cend(),
237 [](const OSDCapGrant& grant) {
238 return grant.allow_all();
239 });
240 }
7c673cae 241
c07f9fc5 242 return (match.is_match_all() && spec.allow_all());
7c673cae
FG
243}
244
11fdf7f2
TL
245bool OSDCapGrant::is_capable(
246 const string& pool_name,
247 const string& ns,
248 const OSDCapPoolTag::app_map_t& application_metadata,
249 const string& object,
250 bool op_may_read,
251 bool op_may_write,
252 const std::vector<OpRequest::ClassInfo>& classes,
253 const entity_addr_t& addr,
254 std::vector<bool>* class_allowed) const
7c673cae 255{
7c673cae 256 osd_rwxa_t allow = 0;
11fdf7f2
TL
257
258 if (network.size() &&
259 (!network_valid ||
260 !network_contains(network_parsed,
261 network_prefix,
262 addr))) {
263 return false;
264 }
265
c07f9fc5
FG
266 if (profile.is_valid()) {
267 return std::any_of(profile_grants.cbegin(), profile_grants.cend(),
268 [&](const OSDCapGrant& grant) {
11fdf7f2
TL
269 return grant.is_capable(pool_name, ns,
270 application_metadata,
271 object, op_may_read,
272 op_may_write, classes, addr,
273 class_allowed);
274 });
c07f9fc5 275 } else {
11fdf7f2 276 if (match.is_match(pool_name, ns, application_metadata, object)) {
c07f9fc5 277 allow = allow | spec.allow;
7c673cae 278 if ((op_may_read && !(allow & OSD_CAP_R)) ||
c07f9fc5
FG
279 (op_may_write && !(allow & OSD_CAP_W))) {
280 return false;
281 }
282 if (!classes.empty()) {
7c673cae 283 // check 'allow *'
c07f9fc5 284 if (spec.allow_all()) {
7c673cae 285 return true;
c07f9fc5
FG
286 }
287
7c673cae 288 // compare this grant to each class in the operation
c07f9fc5 289 for (size_t i = 0; i < classes.size(); ++i) {
11fdf7f2
TL
290 // check 'allow class foo [method_name]'
291 if (!spec.class_name.empty() &&
292 classes[i].class_name == spec.class_name &&
293 (spec.method_name.empty() ||
294 classes[i].method_name == spec.method_name)) {
c07f9fc5 295 (*class_allowed)[i] = true;
7c673cae
FG
296 continue;
297 }
298 // check 'allow x | class-{rw}': must be on whitelist
c07f9fc5 299 if (!classes[i].whitelisted) {
7c673cae 300 continue;
c07f9fc5 301 }
7c673cae
FG
302 if ((classes[i].read && !(allow & OSD_CAP_CLS_R)) ||
303 (classes[i].write && !(allow & OSD_CAP_CLS_W))) {
304 continue;
305 }
c07f9fc5
FG
306 (*class_allowed)[i] = true;
307 }
308 if (!std::all_of(class_allowed->cbegin(), class_allowed->cend(),
309 [](bool v) { return v; })) {
310 return false;
7c673cae 311 }
7c673cae
FG
312 }
313 return true;
314 }
315 }
316 return false;
317}
318
c07f9fc5
FG
319void OSDCapGrant::expand_profile()
320{
321 if (profile.name == "read-only") {
322 // grants READ-ONLY caps to the OSD
323 profile_grants.emplace_back(OSDCapMatch(profile.pool_namespace),
324 OSDCapSpec(osd_rwxa_t(OSD_CAP_R)));
325 return;
326 }
327 if (profile.name == "read-write") {
328 // grants READ-WRITE caps to the OSD
329 profile_grants.emplace_back(OSDCapMatch(profile.pool_namespace),
330 OSDCapSpec(osd_rwxa_t(OSD_CAP_R | OSD_CAP_W)));
331 }
332
333 if (profile.name == "rbd") {
334 // RBD read-write grant
11fdf7f2 335 profile_grants.emplace_back(OSDCapMatch(string(), "rbd_children"),
c07f9fc5 336 OSDCapSpec(osd_rwxa_t(OSD_CAP_CLS_R)));
11fdf7f2 337 profile_grants.emplace_back(OSDCapMatch(string(), "rbd_mirroring"),
c07f9fc5 338 OSDCapSpec(osd_rwxa_t(OSD_CAP_CLS_R)));
494da23a
TL
339 profile_grants.emplace_back(OSDCapMatch(profile.pool_namespace.pool_name),
340 OSDCapSpec("rbd", "metadata_list"));
c07f9fc5
FG
341 profile_grants.emplace_back(OSDCapMatch(profile.pool_namespace),
342 OSDCapSpec(osd_rwxa_t(OSD_CAP_R |
343 OSD_CAP_W |
344 OSD_CAP_X)));
345 }
346 if (profile.name == "rbd-read-only") {
347 // RBD read-only grant
348 profile_grants.emplace_back(OSDCapMatch(profile.pool_namespace),
349 OSDCapSpec(osd_rwxa_t(OSD_CAP_R |
350 OSD_CAP_CLS_R)));
11fdf7f2
TL
351 profile_grants.emplace_back(OSDCapMatch(profile.pool_namespace,
352 "rbd_header."),
353 OSDCapSpec("rbd", "child_attach"));
354 profile_grants.emplace_back(OSDCapMatch(profile.pool_namespace,
355 "rbd_header."),
356 OSDCapSpec("rbd", "child_detach"));
c07f9fc5
FG
357 }
358}
359
360bool OSDCap::allow_all() const
361{
362 for (auto &grant : grants) {
363 if (grant.allow_all()) {
364 return true;
365 }
366 }
367 return false;
368}
369
370void OSDCap::set_allow_all()
371{
372 grants.clear();
373 grants.push_back(OSDCapGrant(OSDCapMatch(), OSDCapSpec(OSD_CAP_ANY)));
374}
375
376bool OSDCap::is_capable(const string& pool_name, const string& ns,
11fdf7f2
TL
377 const OSDCapPoolTag::app_map_t& application_metadata,
378 const string& object,
c07f9fc5 379 bool op_may_read, bool op_may_write,
11fdf7f2
TL
380 const std::vector<OpRequest::ClassInfo>& classes,
381 const entity_addr_t& addr) const
c07f9fc5
FG
382{
383 std::vector<bool> class_allowed(classes.size(), false);
384 for (auto &grant : grants) {
11fdf7f2
TL
385 if (grant.is_capable(pool_name, ns, application_metadata,
386 object, op_may_read, op_may_write, classes, addr,
387 &class_allowed)) {
c07f9fc5
FG
388 return true;
389 }
390 }
391 return false;
392}
393
7c673cae
FG
394
395// grammar
396namespace qi = boost::spirit::qi;
397namespace ascii = boost::spirit::ascii;
398namespace phoenix = boost::phoenix;
399
400template <typename Iterator>
401struct OSDCapParser : qi::grammar<Iterator, OSDCap()>
402{
403 OSDCapParser() : OSDCapParser::base_type(osdcap)
404 {
405 using qi::char_;
406 using qi::int_;
407 using qi::lexeme;
408 using qi::alnum;
409 using qi::_val;
410 using qi::_1;
411 using qi::_2;
412 using qi::_3;
413 using qi::eps;
414 using qi::lit;
415
416 quoted_string %=
417 lexeme['"' >> +(char_ - '"') >> '"'] |
418 lexeme['\'' >> +(char_ - '\'') >> '\''];
419 equoted_string %=
420 lexeme['"' >> *(char_ - '"') >> '"'] |
421 lexeme['\'' >> *(char_ - '\'') >> '\''];
11fdf7f2 422 unquoted_word %= +char_("a-zA-Z0-9_./-");
7c673cae
FG
423 str %= quoted_string | unquoted_word;
424 estr %= equoted_string | unquoted_word;
11fdf7f2 425 network_str %= +char_("/.:a-fA-F0-9][");
7c673cae
FG
426
427 spaces = +ascii::space;
428
11fdf7f2
TL
429 wildcard = (lit('*') | lit("all")) [_val = "*"];
430
7c673cae 431 pool_name %= -(spaces >> lit("pool") >> (lit('=') | spaces) >> str);
11fdf7f2
TL
432 nspace %= (spaces >> lit("namespace")
433 >> (lit('=') | spaces)
434 >> estr >> -char_('*'));
c07f9fc5 435
11fdf7f2 436 // match := [pool[=]<poolname> [namespace[=]<namespace>]] [object_prefix <prefix>]
7c673cae 437 object_prefix %= -(spaces >> lit("object_prefix") >> spaces >> str);
11fdf7f2
TL
438 pooltag %= (spaces >> lit("tag")
439 >> spaces >> str // application
440 >> spaces >> (wildcard | str) // key
441 >> -spaces >> lit('=') >> -spaces >> (wildcard | str)); // value
7c673cae 442
c07f9fc5 443 match = (
11fdf7f2
TL
444 pooltag [_val = phoenix::construct<OSDCapMatch>(_1)] |
445 (nspace >> pooltag) [_val = phoenix::construct<OSDCapMatch>(_1, _2)] |
c07f9fc5 446 (pool_name >> nspace >> object_prefix) [_val = phoenix::construct<OSDCapMatch>(_1, _2, _3)] |
11fdf7f2
TL
447 (pool_name >> object_prefix) [_val = phoenix::construct<OSDCapMatch>(_1, _2)]
448 );
7c673cae
FG
449
450 // rwxa := * | [r][w][x] [class-read] [class-write]
451 rwxa =
11fdf7f2 452 (spaces >> wildcard[_val = OSD_CAP_ANY]) |
7c673cae
FG
453 ( eps[_val = 0] >>
454 (
455 spaces >>
456 ( lit('r')[_val |= OSD_CAP_R] ||
457 lit('w')[_val |= OSD_CAP_W] ||
458 lit('x')[_val |= OSD_CAP_X] )) ||
459 ( (spaces >> lit("class-read")[_val |= OSD_CAP_CLS_R]) ||
460 (spaces >> lit("class-write")[_val |= OSD_CAP_CLS_W]) ));
461
11fdf7f2 462 // capspec := * | rwx | class <name> [<method name>]
c07f9fc5 463 class_name %= (spaces >> lit("class") >> spaces >> str);
11fdf7f2 464 method_name %= -(spaces >> str);
c07f9fc5 465 capspec = (
11fdf7f2
TL
466 (rwxa) [_val = phoenix::construct<OSDCapSpec>(_1)] |
467 (class_name >> method_name) [_val = phoenix::construct<OSDCapSpec>(_1, _2)]);
c07f9fc5
FG
468
469 // profile := profile <name> [pool[=]<pool> [namespace[=]<namespace>]]
470 profile_name %= (lit("profile") >> (lit('=') | spaces) >> str);
471 profile = (
472 (profile_name >> pool_name >> nspace) [_val = phoenix::construct<OSDCapProfile>(_1, _2, _3)] |
473 (profile_name >> pool_name) [_val = phoenix::construct<OSDCapProfile>(_1, _2)]);
7c673cae
FG
474
475 // grant := allow match capspec
c07f9fc5 476 grant = (*ascii::blank >>
11fdf7f2
TL
477 ((lit("allow") >> capspec >> match >>
478 -(spaces >> lit("network") >> spaces >> network_str))
479 [_val = phoenix::construct<OSDCapGrant>(_2, _1, _3)] |
480 (lit("allow") >> match >> capspec >>
481 -(spaces >> lit("network") >> spaces >> network_str))
482 [_val = phoenix::construct<OSDCapGrant>(_1, _2, _3)] |
483 (profile >> -(spaces >> lit("network") >> spaces >> network_str))
484 [_val = phoenix::construct<OSDCapGrant>(_1, _2)]
c07f9fc5 485 ) >> *ascii::blank);
7c673cae
FG
486 // osdcap := grant [grant ...]
487 grants %= (grant % (lit(';') | lit(',')));
c07f9fc5 488 osdcap = grants [_val = phoenix::construct<OSDCap>(_1)];
7c673cae
FG
489 }
490 qi::rule<Iterator> spaces;
491 qi::rule<Iterator, unsigned()> rwxa;
492 qi::rule<Iterator, string()> quoted_string, equoted_string;
493 qi::rule<Iterator, string()> unquoted_word;
11fdf7f2
TL
494 qi::rule<Iterator, string()> str, estr, network_str;
495 qi::rule<Iterator, string()> wildcard;
c07f9fc5 496 qi::rule<Iterator, string()> class_name;
11fdf7f2 497 qi::rule<Iterator, string()> method_name;
7c673cae
FG
498 qi::rule<Iterator, OSDCapSpec()> capspec;
499 qi::rule<Iterator, string()> pool_name;
500 qi::rule<Iterator, string()> nspace;
501 qi::rule<Iterator, string()> object_prefix;
11fdf7f2 502 qi::rule<Iterator, OSDCapPoolTag()> pooltag;
7c673cae 503 qi::rule<Iterator, OSDCapMatch()> match;
c07f9fc5
FG
504 qi::rule<Iterator, string()> profile_name;
505 qi::rule<Iterator, OSDCapProfile()> profile;
7c673cae
FG
506 qi::rule<Iterator, OSDCapGrant()> grant;
507 qi::rule<Iterator, std::vector<OSDCapGrant>()> grants;
508 qi::rule<Iterator, OSDCap()> osdcap;
509};
510
511bool OSDCap::parse(const string& str, ostream *err)
512{
513 OSDCapParser<string::const_iterator> g;
514 string::const_iterator iter = str.begin();
515 string::const_iterator end = str.end();
516
517 bool r = qi::phrase_parse(iter, end, g, ascii::space, *this);
518 if (r && iter == end)
519 return true;
520
521 // Make sure no grants are kept after parsing failed!
522 grants.clear();
523
524 if (err)
11fdf7f2
TL
525 *err << "osd capability parse failed, stopped at '" << std::string(iter, end)
526 << "' of '" << str << "'";
7c673cae
FG
527
528 return false;
529}