Skip to content

Commit

Permalink
Merge pull request #1046 from dachary/wip-7103
Browse files Browse the repository at this point in the history
common: recursive implementation of config::expand_meta …

Reviewed-by: Sage Weil <sage@inktank.com>
  • Loading branch information
Sage Weil committed Jan 7, 2014
2 parents 12a0f51 + 3f34dc7 commit ffc9d72
Show file tree
Hide file tree
Showing 7 changed files with 318 additions and 56 deletions.
120 changes: 76 additions & 44 deletions src/common/config.cc
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
#undef dendl

using std::map;
using std::list;
using std::multimap;
using std::ostringstream;
using std::pair;
Expand Down Expand Up @@ -229,7 +230,7 @@ int md_config_t::parse_config_files_impl(const std::list<std::string> &conf_file
for (c = conf_files.begin(); c != conf_files.end(); ++c) {
cf.clear();
string fn = *c;
expand_meta(fn);
expand_meta(fn, warnings);
int ret = cf.parse_file(fn.c_str(), parse_errors, warnings);
if (ret == 0)
break;
Expand Down Expand Up @@ -440,7 +441,7 @@ int md_config_t::parse_argv(std::vector<const char*>& args)
_exit(1);
}
string s = buf;
expand_meta(s);
expand_meta(s, &std::cerr);
std::cout << s << std::endl;
_exit(0);
}
Expand Down Expand Up @@ -667,7 +668,7 @@ int md_config_t::set_val(const char *key, const char *val, bool meta)

std::string v(val);
if (meta)
expand_meta(v);
expand_meta(v, &std::cerr);

string k(ConfFile::normalize_key_name(key));

Expand Down Expand Up @@ -850,7 +851,7 @@ int md_config_t::_get_val_from_conf_file(const std::vector <std::string> &sectio
int ret = cf.read(s->c_str(), key, out);
if (ret == 0) {
if (emeta)
expand_meta(out);
expand_meta(out, &std::cerr);
return 0;
}
else if (ret != -ENOENT)
Expand Down Expand Up @@ -952,36 +953,70 @@ static const int NUM_CONF_METAVARIABLES =
void md_config_t::expand_all_meta()
{
// Expand all metavariables
ostringstream oss;
for (int i = 0; i < NUM_CONFIG_OPTIONS; i++) {
config_option *opt = config_optionsp + i;
if (opt->type == OPT_STR) {
std::string *str = (std::string *)opt->conf_ptr(this);
expand_meta(*str);
list<config_option *> stack;
expand_meta(*str, opt, stack, &oss);
}
}
cerr << oss.str();
}

bool md_config_t::expand_meta(std::string &origval) const
bool md_config_t::expand_meta(std::string &origval,
std::ostream *oss) const
{
list<config_option *> stack;
return expand_meta(origval, NULL, stack, oss);
}

bool md_config_t::expand_meta(std::string &origval,
config_option *opt,
std::list<config_option *> stack,
std::ostream *oss) const
{
assert(lock.is_locked());
bool found_meta = false;

set<string> resolved;
// no $ means no variable expansion is necessary
if (origval.find("$") == string::npos)
return false;

// ignore an expansion loop and create a human readable
// message about it
if (opt) {
for (list<config_option *>::iterator i = stack.begin();
i != stack.end();
++i) {
if (strcmp(opt->name, (*i)->name) == 0) {
*oss << "variable expansion loop at "
<< opt->name << "=" << origval << std::endl;
*oss << "expansion stack: " << std::endl;
for (list<config_option *>::iterator j = stack.begin();
j != stack.end();
j++) {
*oss << (*j)->name << "=" << *(string *)(*j)->conf_ptr(this) << std::endl;
}
return false;
}
}
}

string val = origval;
if (opt)
stack.push_front(opt);

restart:
bool found_meta = false;
string out;
out.reserve(val.size());

string val = origval;
for (string::size_type s = 0; s < val.size(); ) {
if (val[s] != '$') {
out += val[s++];
continue;
}

// try to parse the variable name into var, either \$\{(.+)\} or
// \$([a-z\_]+)
// \$[a-z\_]+
const char *valid_chars = "abcdefghijklmnopqrstuvwxyz_";
string var;
size_t endpos = 0;
Expand All @@ -1001,8 +1036,8 @@ bool md_config_t::expand_meta(std::string &origval) const
else
var = val.substr(s+1);
}
//cout << "var='" << var << "'" << std::endl;

bool expanded = false;
if (var.length()) {
// special metavariable?
for (int i = 0; i < NUM_CONF_METAVARIABLES; ++i) {
Expand All @@ -1025,42 +1060,39 @@ bool md_config_t::expand_meta(std::string &origval) const
out += stringify(getpid());
else
assert(0); // unreachable
found_meta = true;
if (endpos != std::string::npos)
out += val.substr(endpos);
//cout << "val '" << val << "' s " << s << " out '" << out << "'" << std::endl;
val = out;
goto restart;
expanded = true;
}

// config option?
for (int i = 0; i < NUM_CONFIG_OPTIONS; i++) {
config_option *opt = &config_optionsp[i];
if (var != opt->name)
continue;

// avoid loops
if (resolved.count(opt->name))
continue; // loop; skip
resolved.insert(opt->name);

found_meta = true;
char *vv = NULL;
_get_val(opt->name, &vv, -1);
out += vv;
if (endpos != std::string::npos)
out += val.substr(endpos);
//cout << "val '" << val << "' s " << s << " out '" << out << "' after sub " << opt->name << " -> " << vv << std::endl;
val = out;
free(vv);
goto restart;
if (!expanded) {
// config option?
for (int i = 0; i < NUM_CONFIG_OPTIONS; i++) {
config_option *opt = &config_optionsp[i];
if (var == opt->name) {
if (opt->type == OPT_STR) {
string *origval = (string *)opt->conf_ptr(this);
expand_meta(*origval, opt, stack, oss);
out += *origval;
} else {
char *vv = NULL;
_get_val(opt->name, &vv, -1);
out += vv;
free(vv);
}
expanded = true;
break;
}
}
}
}

// pass it thru
out += val[s++];
if (expanded) {
found_meta = true;
s = endpos;
} else {
out += val[s++];
}
}
//cout << "done '" << origval << "' -> '" << out << "'" << std::endl;
// override the original value with the expanded value
origval = out;
return found_meta;
}
Expand Down
12 changes: 9 additions & 3 deletions src/common/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -173,9 +173,13 @@ struct md_config_t {

void init_subsys();

// Expand metavariables in the provided string.
// Returns true if any metavariables were found and expanded.
bool expand_meta(std::string &val) const;
bool expand_meta(std::string &val,
std::ostream *oss) const;

bool expand_meta(std::string &val,
config_option *opt,
std::list<config_option *> stack,
std::ostream *oss) const;

/// expand all metavariables in config structure.
void expand_all_meta();
Expand Down Expand Up @@ -233,6 +237,8 @@ struct md_config_t {
* It is best if this lock comes first in the lock hierarchy. We will
* hold this lock when calling configuration observers. */
mutable Mutex lock;

friend class test_md_config_t;
};

typedef enum {
Expand Down
5 changes: 5 additions & 0 deletions src/test/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -535,6 +535,11 @@ unittest_confutils_LDADD = $(UNITTEST_LDADD) $(CEPH_GLOBAL)
unittest_confutils_CXXFLAGS = $(UNITTEST_CXXFLAGS)
check_PROGRAMS += unittest_confutils

unittest_config_SOURCES = test/common/test_config.cc
unittest_config_LDADD = $(UNITTEST_LDADD) $(CEPH_GLOBAL)
unittest_config_CXXFLAGS = $(UNITTEST_CXXFLAGS)
check_PROGRAMS += unittest_config

unittest_heartbeatmap_SOURCES = test/heartbeat_map.cc
unittest_heartbeatmap_LDADD = $(LIBCOMMON) $(UNITTEST_LDADD) $(CEPH_GLOBAL)
unittest_heartbeatmap_CXXFLAGS = $(UNITTEST_CXXFLAGS)
Expand Down
10 changes: 10 additions & 0 deletions src/test/cli/ceph-conf/show-config-value.t
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,13 @@
$ ceph-conf -n osd.0 --show-config-value INVALID -c /dev/null
failed to get config option 'INVALID': option not found
[1]
$ echo '[global]' > $TESTDIR/ceph.conf
$ echo 'mon_host=$public_network' >> $TESTDIR/ceph.conf
$ echo 'public_network=$mon_host' >> $TESTDIR/ceph.conf
$ ceph-conf --show-config-value mon_host -c $TESTDIR/ceph.conf
variable expansion loop at public_network=$mon_host
expansion stack:
mon_host=$public_network
public_network=$mon_host
$mon_host
$ rm $TESTDIR/ceph.conf

0 comments on commit ffc9d72

Please sign in to comment.