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(ret
, -EINVAL
);
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(ret
, -ENOSYS
);
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
));
220 TEST(DaemonConfig
, InjectArgsBooleans
) {
225 // Change log_to_syslog
226 std::string
injection("--log_to_syslog --log-graylog-port 28");
227 ret
= g_ceph_context
->_conf
->injectargs(injection
, &cout
);
230 // log_to_syslog should be set...
231 memset(buf
, 0, sizeof(buf
));
232 ret
= g_ceph_context
->_conf
->get_val("log_to_syslog", &tmp
, sizeof(buf
));
234 ASSERT_EQ(string("true"), string(buf
));
236 // Turn off log_to_syslog
237 injection
= "--log_to_syslog=false --log-graylog-port 28";
238 ret
= g_ceph_context
->_conf
->injectargs(injection
, &cout
);
241 // log_to_syslog should be cleared...
242 memset(buf
, 0, sizeof(buf
));
243 ret
= g_ceph_context
->_conf
->get_val("log_to_syslog", &tmp
, sizeof(buf
));
245 ASSERT_EQ(string("false"), string(buf
));
247 // Turn on log_to_syslog
248 injection
= "--log-graylog-port=1 --log_to_syslog=true --leveldb-max-open-files 40";
249 ret
= g_ceph_context
->_conf
->injectargs(injection
, &cout
);
252 // log_to_syslog should be set...
253 memset(buf
, 0, sizeof(buf
));
254 ret
= g_ceph_context
->_conf
->get_val("log_to_syslog", &tmp
, sizeof(buf
));
256 ASSERT_EQ(string("true"), string(buf
));
259 injection
= "--log-graylog-port 1 --log_to_syslog=falsey --leveldb-max-open-files 42";
260 ret
= g_ceph_context
->_conf
->injectargs(injection
, &cout
);
261 ASSERT_EQ(ret
, -EINVAL
);
263 // log_to_syslog should still be set...
264 memset(buf
, 0, sizeof(buf
));
265 ret
= g_ceph_context
->_conf
->get_val("log_to_syslog", &tmp
, sizeof(buf
));
267 ASSERT_EQ(string("true"), string(buf
));
269 // debug-ms should still become 42...
270 memset(buf
, 0, sizeof(buf
));
271 ret
= g_ceph_context
->_conf
->get_val("leveldb_max_open_files", &tmp
, sizeof(buf
));
273 ASSERT_EQ(string("42"), string(buf
));
276 TEST(DaemonConfig
, InjectArgsLogfile
) {
278 char tmpfile
[PATH_MAX
];
279 const char *tmpdir
= getenv("TMPDIR");
282 snprintf(tmpfile
, sizeof(tmpfile
), "%s/daemon_config_test.%d",
284 std::string
injection("--log_file ");
285 injection
+= tmpfile
;
286 // We're allowed to change log_file because there is an observer.
287 ret
= g_ceph_context
->_conf
->injectargs(injection
, &cout
);
290 // It should have taken effect.
293 memset(buf
, 0, sizeof(buf
));
294 ret
= g_ceph_context
->_conf
->get_val("log_file", &tmp
, sizeof(buf
));
296 ASSERT_EQ(string(buf
), string(tmpfile
));
298 // The logfile should exist.
299 ASSERT_EQ(access(tmpfile
, R_OK
), 0);
301 // Let's turn off the logfile.
302 ret
= g_ceph_context
->_conf
->set_val("log_file", "");
304 g_ceph_context
->_conf
->apply_changes(NULL
);
305 ret
= g_ceph_context
->_conf
->get_val("log_file", &tmp
, sizeof(buf
));
307 ASSERT_EQ(string(""), string(buf
));
309 // Clean up the garbage
313 TEST(DaemonConfig
, ThreadSafety1
) {
315 // Verify that we can't change this, since internal_safe_to_start_threads has
317 ret
= g_ceph_context
->_conf
->set_val("osd_data", "");
318 ASSERT_EQ(ret
, -ENOSYS
);
320 ASSERT_EQ(0, g_ceph_context
->_conf
->set_val("internal_safe_to_start_threads",
323 // Ok, now we can change this. Since this is just a test, and there are no
324 // OSD threads running, we know changing osd_data won't actually blow up the
326 ret
= g_ceph_context
->_conf
->set_val("osd_data", "/tmp/crazydata");
331 memset(buf
, 0, sizeof(buf
));
332 ret
= g_ceph_context
->_conf
->get_val("osd_data", &tmp
, sizeof(buf
));
334 ASSERT_EQ(string("/tmp/crazydata"), string(buf
));
336 ASSERT_EQ(0, g_ceph_context
->_conf
->set_val("internal_safe_to_start_threads",
341 TEST(DaemonConfig
, InvalidIntegers
) {
343 int ret
= g_ceph_context
->_conf
->set_val("log_graylog_port", "rhubarb");
344 ASSERT_EQ(ret
, -EINVAL
);
348 int64_t max
= std::numeric_limits
<int64_t>::max();
349 string str
= boost::lexical_cast
<string
>(max
);
350 str
= str
+ "999"; // some extra digits to take us out of bounds
351 int ret
= g_ceph_context
->_conf
->set_val("log_graylog_port", str
);
352 ASSERT_EQ(ret
, -EINVAL
);
356 TEST(DaemonConfig
, InvalidFloats
) {
358 double bad_value
= 2 * (double)std::numeric_limits
<float>::max();
359 string str
= boost::lexical_cast
<string
>(-bad_value
);
360 int ret
= g_ceph_context
->_conf
->set_val("log_stop_at_utilization", str
);
361 ASSERT_EQ(ret
, -EINVAL
);
364 double bad_value
= 2 * (double)std::numeric_limits
<float>::max();
365 string str
= boost::lexical_cast
<string
>(bad_value
);
366 int ret
= g_ceph_context
->_conf
->set_val("log_stop_at_utilization", str
);
367 ASSERT_EQ(ret
, -EINVAL
);
370 int ret
= g_ceph_context
->_conf
->set_val("log_stop_at_utilization", "not a float");
371 ASSERT_EQ(ret
, -EINVAL
);
377 * compile-command: "cd .. ; make unittest_daemon_config && ./unittest_daemon_config"