summaryrefslogtreecommitdiffstats
path: root/src/mon/ConfigMap.h
blob: 34af942a61e05d3336a4d714d1a558d4baea9833 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
// vim: ts=8 sw=2 smarttab

#pragma once

#include <map>
#include <optional>
#include <ostream>
#include <string>

#include "include/utime.h"
#include "common/options.h"
#include "common/entity_name.h"

class CrushWrapper;

// the precedence is thus:
//
//  global
//   crush location (coarse to fine, ordered by type id)
//  daemon type (e.g., osd)
//   device class (osd only)
//   crush location (coarse to fine, ordered by type id)
//  daemon name (e.g., mds.foo)
//
// Note that this means that if we have
//
//  config/host:foo/a = 1
//  config/osd/rack:foo/a = 2
//
// then we get a = 2.  The osd-level config wins, even though rack
// is less precise than host, because the crush limiters are only
// resolved within a section (global, per-daemon, per-instance).

struct OptionMask {
  std::string location_type, location_value; ///< matches crush_location
  std::string device_class;                  ///< matches device class

  bool empty() const {
    return location_type.size() == 0
      && location_value.size() == 0
      && device_class.size() == 0;
  }

  std::string to_str() const {
    std::string r;
    if (location_type.size()) {
      r += location_type + ":" + location_value;
    }
    if (device_class.size()) {
      if (r.size()) {
	r += "/";
      }
      r += "class:" + device_class;
    }
    return r;
  }
  void dump(ceph::Formatter *f) const;
};

struct MaskedOption {
  std::string raw_value;               ///< raw, unparsed, unvalidated value
  const Option *opt;              ///< the option
  OptionMask mask;
  std::unique_ptr<const Option> unknown_opt; ///< if fabricated for an unknown option
  std::string localized_name;     ///< localized name for the option

  MaskedOption(const Option *o, bool fab=false) : opt(o) {
    if (fab) {
      unknown_opt.reset(o);
    }
  }
  MaskedOption(MaskedOption&& o) {
    raw_value = std::move(o.raw_value);
    opt = o.opt;
    mask = std::move(o.mask);
    unknown_opt = std::move(o.unknown_opt);
    localized_name = std::move(o.localized_name);
  }
  const MaskedOption& operator=(const MaskedOption& o) = delete;
  const MaskedOption& operator=(MaskedOption&& o) = delete;

  /// return a precision metric (smaller is more precise)
  int get_precision(const CrushWrapper *crush);

  friend std::ostream& operator<<(std::ostream& out, const MaskedOption& o);

  void dump(ceph::Formatter *f) const;
};

struct Section {
  std::multimap<std::string,MaskedOption> options;

  void clear() {
    options.clear();
  }
  void dump(ceph::Formatter *f) const;
  std::string get_minimal_conf() const;
};

struct ConfigMap {
  Section global;
  std::map<std::string,Section, std::less<>> by_type;
  std::map<std::string,Section, std::less<>> by_id;
  std::list<std::unique_ptr<Option>> stray_options;

  Section *find_section(const std::string& name) {
    if (name == "global") {
      return &global;
    }
    auto i = by_type.find(name);
    if (i != by_type.end()) {
      return &i->second;
    }
    i = by_id.find(name);
    if (i != by_id.end()) {
      return &i->second;
    }
    return nullptr;
  }
  void clear() {
    global.clear();
    by_type.clear();
    by_id.clear();
    stray_options.clear();
  }
  void dump(ceph::Formatter *f) const;
  std::map<std::string,std::string,std::less<>> generate_entity_map(
    const EntityName& name,
    const std::map<std::string,std::string>& crush_location,
    const CrushWrapper *crush,
    const std::string& device_class,
    std::map<std::string,std::pair<std::string,const MaskedOption*>> *src=0);

  void parse_key(
    const std::string& key,
    std::string *name,
    std::string *who);
  static bool parse_mask(
    const std::string& in,
    std::string *section,
    OptionMask *mask);
};


struct ConfigChangeSet {
  version_t version;
  utime_t stamp;
  std::string name;

  // key -> (old value, new value)
  std::map<std::string,std::pair<std::optional<std::string>,std::optional<std::string>>> diff;

  void dump(ceph::Formatter *f) const;
  void print(std::ostream& out) const;
};