1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
4 * Ceph - scalable distributed file system
6 * Copyright (C) 2011 New Dream Network
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.
15 #include "gtest/gtest.h"
16 #include "common/ceph_argparse.h"
17 #include "common/config.h"
18 #include "global/global_context.h"
19 #include "include/cephfs/libcephfs.h"
20 #include "include/rados/librados.h"
27 #include <boost/lexical_cast.hpp>
32 TEST(DaemonConfig, SimpleSet) {
34 ret = g_ceph_context->_conf->set_val("log_graylog_port", "21");
36 g_ceph_context->_conf->apply_changes(NULL);
38 memset(buf, 0, sizeof(buf));
40 ret = g_ceph_context->_conf->get_val("log_graylog_port", &tmp, sizeof(buf));
42 ASSERT_EQ(string("21"), string(buf));
45 TEST(DaemonConfig, Substitution) {
47 ret = g_ceph_context->_conf->set_val("internal_safe_to_start_threads", "false");
49 ret = g_ceph_context->_conf->set_val("host", "foo");
51 ret = g_ceph_context->_conf->set_val("public_network", "bar$host.baz", false);
53 g_ceph_context->_conf->apply_changes(NULL);
55 memset(buf, 0, sizeof(buf));
57 ret = g_ceph_context->_conf->get_val("public_network", &tmp, sizeof(buf));
59 ASSERT_EQ(string("barfoo.baz"), string(buf));
62 TEST(DaemonConfig, SubstitutionTrailing) {
64 ret = g_ceph_context->_conf->set_val("internal_safe_to_start_threads", "false");
66 ret = g_ceph_context->_conf->set_val("host", "foo");
68 ret = g_ceph_context->_conf->set_val("public_network", "bar$host", false);
70 g_ceph_context->_conf->apply_changes(NULL);
72 memset(buf, 0, sizeof(buf));
74 ret = g_ceph_context->_conf->get_val("public_network", &tmp, sizeof(buf));
76 ASSERT_EQ(string("barfoo"), string(buf));
79 TEST(DaemonConfig, SubstitutionBraces) {
81 ret = g_ceph_context->_conf->set_val("internal_safe_to_start_threads", "false");
83 ret = g_ceph_context->_conf->set_val("host", "foo");
85 ret = g_ceph_context->_conf->set_val("public_network", "bar${host}baz", false);
87 g_ceph_context->_conf->apply_changes(NULL);
89 memset(buf, 0, sizeof(buf));
91 ret = g_ceph_context->_conf->get_val("public_network", &tmp, sizeof(buf));
93 ASSERT_EQ(string("barfoobaz"), string(buf));
95 TEST(DaemonConfig, SubstitutionBracesTrailing) {
97 ret = g_ceph_context->_conf->set_val("internal_safe_to_start_threads", "false");
99 ret = g_ceph_context->_conf->set_val("host", "foo");
101 ret = g_ceph_context->_conf->set_val("public_network", "bar${host}", false);
103 g_ceph_context->_conf->apply_changes(NULL);
105 memset(buf, 0, sizeof(buf));
107 ret = g_ceph_context->_conf->get_val("public_network", &tmp, sizeof(buf));
109 ASSERT_EQ(string("barfoo"), string(buf));
112 // config: variable substitution happen only once http://tracker.ceph.com/issues/7103
113 TEST(DaemonConfig, SubstitutionMultiple) {
115 ret = g_ceph_context->_conf->set_val("mon_host", "localhost", false);
117 ret = g_ceph_context->_conf->set_val("keyring", "$mon_host/$cluster.keyring,$mon_host/$cluster.mon.keyring", false);
119 g_ceph_context->_conf->apply_changes(NULL);
121 memset(buf, 0, sizeof(buf));
123 ret = g_ceph_context->_conf->get_val("keyring", &tmp, sizeof(buf));
125 ASSERT_EQ(string("localhost/ceph.keyring,localhost/ceph.mon.keyring"), tmp);
126 ASSERT_TRUE(strchr(buf, '$') == NULL);
129 TEST(DaemonConfig, ArgV) {
130 ASSERT_EQ(0, g_ceph_context->_conf->set_val("internal_safe_to_start_threads",
134 const char *argv[] = { "foo", "--log-graylog-port", "22",
135 "--keyfile", "/tmp/my-keyfile", NULL };
136 size_t argc = (sizeof(argv) / sizeof(argv[0])) - 1;
137 vector<const char*> args;
138 argv_to_vec(argc, argv, args);
139 g_ceph_context->_conf->parse_argv(args);
140 g_ceph_context->_conf->apply_changes(NULL);
144 memset(buf, 0, sizeof(buf));
145 ret = g_ceph_context->_conf->get_val("keyfile", &tmp, sizeof(buf));
147 ASSERT_EQ(string("/tmp/my-keyfile"), string(buf));
149 memset(buf, 0, sizeof(buf));
150 ret = g_ceph_context->_conf->get_val("log_graylog_port", &tmp, sizeof(buf));
152 ASSERT_EQ(string("22"), string(buf));
154 ASSERT_EQ(0, g_ceph_context->_conf->set_val("internal_safe_to_start_threads",
158 TEST(DaemonConfig, InjectArgs) {
160 std::string injection("--log-graylog-port 56 --leveldb-max-open-files 42");
161 ret = g_ceph_context->_conf->injectargs(injection, &cout);
166 memset(buf, 0, sizeof(buf));
167 ret = g_ceph_context->_conf->get_val("leveldb_max_open_files", &tmp, sizeof(buf));
169 ASSERT_EQ(string("42"), string(buf));
171 memset(buf, 0, sizeof(buf));
172 ret = g_ceph_context->_conf->get_val("log_graylog_port", &tmp, sizeof(buf));
174 ASSERT_EQ(string("56"), string(buf));
176 injection = "--log-graylog-port 57";
177 ret = g_ceph_context->_conf->injectargs(injection, &cout);
179 ret = g_ceph_context->_conf->get_val("log_graylog_port", &tmp, sizeof(buf));
181 ASSERT_EQ(string("57"), string(buf));
184 TEST(DaemonConfig, InjectArgsReject) {
191 // We should complain about the garbage in the input
192 std::string injection("--random-garbage-in-injectargs 26 --log-graylog-port 28");
193 ret = g_ceph_context->_conf->injectargs(injection, &cout);
194 ASSERT_EQ(-EINVAL, ret);
196 // But, debug should still be set...
197 memset(buf, 0, sizeof(buf));
198 ret = g_ceph_context->_conf->get_val("log_graylog_port", &tmp, sizeof(buf));
200 ASSERT_EQ(string("28"), string(buf));
202 // What's the current value of osd_data?
203 memset(buf, 0, sizeof(buf));
204 ret = g_ceph_context->_conf->get_val("osd_data", &tmp, sizeof(buf));
207 // Injectargs shouldn't let us change this, since it is a string-valued
208 // variable and there isn't an observer for it.
209 std::string injection2("--osd_data /tmp/some-other-directory --log-graylog-port 4");
210 ret = g_ceph_context->_conf->injectargs(injection2, &cout);
211 ASSERT_EQ(-ENOSYS, ret);
213 // It should be unchanged.
214 memset(buf2, 0, sizeof(buf2));
215 ret = g_ceph_context->_conf->get_val("osd_data", &tmp2, sizeof(buf2));
217 ASSERT_EQ(string(buf), string(buf2));
219 // We should complain about the missing arguments.
220 std::string injection3("--log-graylog-port 28 --debug_ms");
221 ret = g_ceph_context->_conf->injectargs(injection3, &cout);
222 ASSERT_EQ(-EINVAL, ret);
225 TEST(DaemonConfig, InjectArgsBooleans) {
230 // Change log_to_syslog
231 std::string injection("--log_to_syslog --log-graylog-port 28");
232 ret = g_ceph_context->_conf->injectargs(injection, &cout);
235 // log_to_syslog should be set...
236 memset(buf, 0, sizeof(buf));
237 ret = g_ceph_context->_conf->get_val("log_to_syslog", &tmp, sizeof(buf));
239 ASSERT_EQ(string("true"), string(buf));
241 // Turn off log_to_syslog
242 injection = "--log_to_syslog=false --log-graylog-port 28";
243 ret = g_ceph_context->_conf->injectargs(injection, &cout);
246 // log_to_syslog should be cleared...
247 memset(buf, 0, sizeof(buf));
248 ret = g_ceph_context->_conf->get_val("log_to_syslog", &tmp, sizeof(buf));
250 ASSERT_EQ(string("false"), string(buf));
252 // Turn on log_to_syslog
253 injection = "--log-graylog-port=1 --log_to_syslog=true --leveldb-max-open-files 40";
254 ret = g_ceph_context->_conf->injectargs(injection, &cout);
257 // log_to_syslog should be set...
258 memset(buf, 0, sizeof(buf));
259 ret = g_ceph_context->_conf->get_val("log_to_syslog", &tmp, sizeof(buf));
261 ASSERT_EQ(string("true"), string(buf));
264 injection = "--log-graylog-port 1 --log_to_syslog=falsey --leveldb-max-open-files 42";
265 ret = g_ceph_context->_conf->injectargs(injection, &cout);
266 ASSERT_EQ(-EINVAL, ret);
268 // log_to_syslog should still be set...
269 memset(buf, 0, sizeof(buf));
270 ret = g_ceph_context->_conf->get_val("log_to_syslog", &tmp, sizeof(buf));
272 ASSERT_EQ(string("true"), string(buf));
274 // debug-ms should still become 42...
275 memset(buf, 0, sizeof(buf));
276 ret = g_ceph_context->_conf->get_val("leveldb_max_open_files", &tmp, sizeof(buf));
278 ASSERT_EQ(string("42"), string(buf));
281 TEST(DaemonConfig, InjectArgsLogfile) {
283 char tmpfile[PATH_MAX];
284 const char *tmpdir = getenv("TMPDIR");
287 snprintf(tmpfile, sizeof(tmpfile), "%s/daemon_config_test.%d",
289 std::string injection("--log_file ");
290 injection += tmpfile;
291 // We're allowed to change log_file because there is an observer.
292 ret = g_ceph_context->_conf->injectargs(injection, &cout);
295 // It should have taken effect.
298 memset(buf, 0, sizeof(buf));
299 ret = g_ceph_context->_conf->get_val("log_file", &tmp, sizeof(buf));
301 ASSERT_EQ(string(buf), string(tmpfile));
303 // The logfile should exist.
304 ASSERT_EQ(0, access(tmpfile, R_OK));
306 // Let's turn off the logfile.
307 ret = g_ceph_context->_conf->set_val("log_file", "");
309 g_ceph_context->_conf->apply_changes(NULL);
310 ret = g_ceph_context->_conf->get_val("log_file", &tmp, sizeof(buf));
312 ASSERT_EQ(string(""), string(buf));
314 // Clean up the garbage
318 TEST(DaemonConfig, ThreadSafety1) {
320 // Verify that we can't change this, since internal_safe_to_start_threads has
322 ret = g_ceph_context->_conf->set_val("osd_data", "");
323 ASSERT_EQ(-ENOSYS, ret);
325 ASSERT_EQ(0, g_ceph_context->_conf->set_val("internal_safe_to_start_threads",
328 // Ok, now we can change this. Since this is just a test, and there are no
329 // OSD threads running, we know changing osd_data won't actually blow up the
331 ret = g_ceph_context->_conf->set_val("osd_data", "/tmp/crazydata");
336 memset(buf, 0, sizeof(buf));
337 ret = g_ceph_context->_conf->get_val("osd_data", &tmp, sizeof(buf));
339 ASSERT_EQ(string("/tmp/crazydata"), string(buf));
341 ASSERT_EQ(0, g_ceph_context->_conf->set_val("internal_safe_to_start_threads",
346 TEST(DaemonConfig, InvalidIntegers) {
348 int ret = g_ceph_context->_conf->set_val("log_graylog_port", "rhubarb");
349 ASSERT_EQ(-EINVAL, ret);
353 int64_t max = std::numeric_limits<int64_t>::max();
354 string str = boost::lexical_cast<string>(max);
355 str = str + "999"; // some extra digits to take us out of bounds
356 int ret = g_ceph_context->_conf->set_val("log_graylog_port", str);
357 ASSERT_EQ(-EINVAL, ret);
361 TEST(DaemonConfig, InvalidFloats) {
363 double bad_value = 2 * (double)std::numeric_limits<float>::max();
364 string str = boost::lexical_cast<string>(-bad_value);
365 int ret = g_ceph_context->_conf->set_val("log_stop_at_utilization", str);
366 ASSERT_EQ(-EINVAL, ret);
369 double bad_value = 2 * (double)std::numeric_limits<float>::max();
370 string str = boost::lexical_cast<string>(bad_value);
371 int ret = g_ceph_context->_conf->set_val("log_stop_at_utilization", str);
372 ASSERT_EQ(-EINVAL, ret);
375 int ret = g_ceph_context->_conf->set_val("log_stop_at_utilization", "not a float");
376 ASSERT_EQ(-EINVAL, ret);
382 * compile-command: "cd .. ; make unittest_daemon_config && ./unittest_daemon_config"