]>
git.proxmox.com Git - ceph.git/blob - ceph/src/test/confutils.cc
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.
14 #include "common/ConfUtils.h"
15 #include "common/config_proxy.h"
16 #include "common/errno.h"
17 #include "gtest/gtest.h"
18 #include "include/buffer.h"
28 #include <sys/types.h>
30 namespace fs
= std::filesystem
;
33 using ceph::bufferlist
;
35 using std::ostringstream
;
37 #define MAX_FILES_TO_DELETE 1000UL
39 static size_t config_idx
= 0;
40 static size_t unlink_idx
= 0;
41 static char *to_unlink
[MAX_FILES_TO_DELETE
];
43 static std::string
get_temp_dir()
45 static std::string temp_dir
;
47 if (temp_dir
.empty()) {
48 const char *tmpdir
= getenv("TMPDIR");
53 oss
<< tmpdir
<< "/confutils_test_dir." << rand() << "." << getpid();
55 if (!fs::exists(oss
.str())) {
57 if (!fs::create_directory(oss
.str(), ec
)) {
58 cerr
<< "failed to create temp directory '" << temp_dir
<< "' "
59 << ec
.message() << std::endl
;
62 fs::permissions(oss
.str(), fs::perms::sticky_bit
| fs::perms::all
);
69 static void unlink_all(void)
71 for (size_t i
= 0; i
< unlink_idx
; ++i
) {
74 for (size_t i
= 0; i
< unlink_idx
; ++i
) {
77 rmdir(get_temp_dir().c_str());
80 static int create_tempfile(const std::string
&fname
, const char *text
)
82 FILE *fp
= fopen(fname
.c_str(), "w");
85 cerr
<< "Failed to write file '" << fname
<< "' to temp directory '"
86 << get_temp_dir() << "'. " << cpp_strerror(err
) << std::endl
;
89 std::shared_ptr
<FILE> fpp(fp
, fclose
);
90 if (unlink_idx
>= MAX_FILES_TO_DELETE
)
92 if (unlink_idx
== 0) {
93 memset(to_unlink
, 0, sizeof(to_unlink
));
96 to_unlink
[unlink_idx
++] = strdup(fname
.c_str());
97 size_t strlen_text
= strlen(text
);
98 size_t res
= fwrite(text
, 1, strlen_text
, fp
);
99 if (res
!= strlen_text
) {
101 cerr
<< "fwrite error while writing to " << fname
102 << ": " << cpp_strerror(err
) << std::endl
;
108 static std::string
next_tempfile(const char *text
)
111 std::string
temp_dir(get_temp_dir());
112 if (temp_dir
.empty())
114 oss
<< temp_dir
<< "/test_config." << config_idx
++ << ".config";
115 int ret
= create_tempfile(oss
.str(), text
);
121 const char * const trivial_conf_1
= "";
123 const char * const trivial_conf_2
= "log dir = foobar";
125 const char * const trivial_conf_3
= "log dir = barfoo\n";
127 const char * const trivial_conf_4
= "log dir = \"barbaz\"\n";
129 const char * const simple_conf_1
= "\
130 ; here's a comment\n\
132 keyring = .my_ceph_keyring\n\
136 log per instance = true\n\
137 log sym history = 100\n\
138 profiling logger = true\n\
139 profiling logger dir = wowsers\n\
141 pid file = out/$name.pid\n\
143 mds debug frag = true\n\
145 pid file = out/$name.pid\n\
146 osd scrub load threshold = 5.0\n\
150 osd data = dev/osd0\n\
151 osd journal size = 100\n\
157 // we can add whitespace at odd locations and it will get stripped out.
158 const char * const simple_conf_2
= "\
160 log dir = special_mds_a\n\
162 log sym history = 100\n\
163 log dir = out # after a comment, anything # can ### happen ;;; right?\n\
164 log per instance = true\n\
165 profiling logger = true\n\
166 profiling logger dir = log\n\
170 keyring = osd_keyring ; osd's keyring\n\
174 # I like pound signs as comment markers.\n\
175 ; Do you like pound signs as comment markers?\n\
176 keyring = shenanigans ; The keyring of a leprechaun\n\
178 # Let's just have a line with a lot of whitespace and nothing else.\n\
183 // test line-combining
184 const char * const conf3
= "\
186 log file = /quite/a/long/path\\\n\
191 [mon] #nothing here \n\
194 const char * const escaping_conf_1
= "\
196 log file = the \"scare quotes\"\n\
200 keyring = \"nested \\\"quotes\\\"\"\n\
203 const char * const escaping_conf_2
= "\
205 log file = floppy disk\n\
207 keyring = \"backslash\\\\\"\n\
210 // illegal because it contains an invalid utf8 sequence.
211 const char illegal_conf1
[] = "\
214 pid file = invalid-utf-\xe2\x28\xa1\n\
216 keyring = osd_keyring ; osd's keyring\n\
219 // illegal because it contains a malformed section header.
220 const char illegal_conf2
[] = "\
224 keyring = osd_keyring ; osd's keyring\n\
227 // illegal because it contains a line that doesn't parse
228 const char illegal_conf3
[] = "\
232 keyring = osd_keyring ; osd's keyring\n\
235 // illegal because it has unterminated quotes
236 const char illegal_conf4
[] = "\
238 keyring = \"unterminated quoted string\n\
240 keyring = osd_keyring ; osd's keyring\n\
243 const char override_config_1
[] = "\
245 log file = global_log\n\
247 log file = mds_log\n\
249 log file = osd_log\n\
251 log file = osd0_log\n\
254 const char dup_key_config_1
[] = "\
260 TEST(ConfUtils
, ParseFiles0
) {
264 std::ostringstream err
;
265 std::string
trivial_conf_1_f(next_tempfile(trivial_conf_1
));
267 ASSERT_EQ(cf1
.parse_file(trivial_conf_1_f
.c_str(), &err
), 0);
268 ASSERT_EQ(err
.tellp(), 0U);
271 std::ostringstream err
;
272 std::string
trivial_conf_2_f(next_tempfile(trivial_conf_2
));
274 ASSERT_EQ(cf2
.parse_file(trivial_conf_2_f
.c_str(), &err
), -EINVAL
);
275 ASSERT_GT(err
.tellp(), 0U);
278 std::ostringstream err
;
280 bl3
.append(trivial_conf_3
, strlen(trivial_conf_3
));
282 ASSERT_EQ(cf3
.parse_bufferlist(&bl3
, &err
), 0);
283 ASSERT_EQ(err
.tellp(), 0U);
284 ASSERT_EQ(cf3
.read("global", "log dir", val
), 0);
285 ASSERT_EQ(val
, "barfoo");
288 std::ostringstream err
;
289 std::string
trivial_conf_4_f(next_tempfile(trivial_conf_4
));
291 ASSERT_EQ(cf4
.parse_file(trivial_conf_4_f
.c_str(), &err
), 0);
292 ASSERT_EQ(err
.tellp(), 0U);
293 ASSERT_EQ(cf4
.read("global", "log dir", val
), 0);
294 ASSERT_EQ(val
, "barbaz");
298 TEST(ConfUtils
, ParseFiles1
) {
299 std::ostringstream err
;
300 std::string
simple_conf_1_f(next_tempfile(simple_conf_1
));
302 ASSERT_EQ(cf1
.parse_file(simple_conf_1_f
.c_str(), &err
), 0);
303 ASSERT_EQ(err
.tellp(), 0U);
305 std::string
simple_conf_2_f(next_tempfile(simple_conf_1
));
307 ASSERT_EQ(cf2
.parse_file(simple_conf_2_f
.c_str(), &err
), 0);
308 ASSERT_EQ(err
.tellp(), 0U);
311 bl3
.append(simple_conf_1
, strlen(simple_conf_1
));
313 ASSERT_EQ(cf3
.parse_bufferlist(&bl3
, &err
), 0);
314 ASSERT_EQ(err
.tellp(), 0U);
317 bl4
.append(simple_conf_2
, strlen(simple_conf_2
));
319 ASSERT_EQ(cf4
.parse_bufferlist(&bl4
, &err
), 0);
320 ASSERT_EQ(err
.tellp(), 0U);
323 TEST(ConfUtils
, ReadFiles1
) {
324 std::ostringstream err
;
325 std::string
simple_conf_1_f(next_tempfile(simple_conf_1
));
327 ASSERT_EQ(cf1
.parse_file(simple_conf_1_f
.c_str(), &err
), 0);
328 ASSERT_EQ(err
.tellp(), 0U);
331 ASSERT_EQ(cf1
.read("global", "keyring", val
), 0);
332 ASSERT_EQ(val
, ".my_ceph_keyring");
334 ASSERT_EQ(cf1
.read("mds", "profiling logger dir", val
), 0);
335 ASSERT_EQ(val
, "wowsers");
337 ASSERT_EQ(cf1
.read("mds", "something that does not exist", val
), -ENOENT
);
339 // exists in mds section, but not in global
340 ASSERT_EQ(cf1
.read("global", "profiling logger dir", val
), -ENOENT
);
343 bl2
.append(simple_conf_2
, strlen(simple_conf_2
));
345 ASSERT_EQ(cf2
.parse_bufferlist(&bl2
, &err
), 0);
346 ASSERT_EQ(err
.tellp(), 0U);
347 ASSERT_EQ(cf2
.read("osd0", "keyring", val
), 0);
348 ASSERT_EQ(val
, "osd_keyring");
350 ASSERT_EQ(cf2
.read("mds", "pid file", val
), 0);
351 ASSERT_EQ(val
, "foo2");
352 ASSERT_EQ(cf2
.read("nonesuch", "keyring", val
), -ENOENT
);
355 TEST(ConfUtils
, ReadFiles2
) {
356 std::ostringstream err
;
357 std::string
conf3_f(next_tempfile(conf3
));
360 ASSERT_EQ(cf1
.parse_file(conf3_f
.c_str(), &err
), 0);
361 ASSERT_EQ(err
.tellp(), 0U);
362 ASSERT_EQ(cf1
.read("global", "log file", val
), 0);
363 ASSERT_EQ(val
, "/quite/a/long/path/for/a/log/file");
364 ASSERT_EQ(cf1
.read("global", "pid file", val
), 0);
365 ASSERT_EQ(val
, "spork");
368 TEST(ConfUtils
, IllegalFiles
) {
370 std::ostringstream err
;
372 std::string
illegal_conf1_f(next_tempfile(illegal_conf1
));
373 ASSERT_EQ(cf1
.parse_file(illegal_conf1_f
.c_str(), &err
), -EINVAL
);
374 ASSERT_GT(err
.tellp(), 0U);
377 std::ostringstream err
;
379 bl2
.append(illegal_conf2
, strlen(illegal_conf2
));
381 ASSERT_EQ(cf2
.parse_bufferlist(&bl2
, &err
), -EINVAL
);
382 ASSERT_GT(err
.tellp(), 0U);
385 std::ostringstream err
;
386 std::string
illegal_conf3_f(next_tempfile(illegal_conf3
));
388 ASSERT_EQ(cf3
.parse_file(illegal_conf3_f
.c_str(), &err
), -EINVAL
);
389 ASSERT_GT(err
.tellp(), 0U);
392 std::ostringstream err
;
393 std::string
illegal_conf4_f(next_tempfile(illegal_conf4
));
395 ASSERT_EQ(cf4
.parse_file(illegal_conf4_f
.c_str(), &err
), -EINVAL
);
396 ASSERT_GT(err
.tellp(), 0U);
400 TEST(ConfUtils
, EscapingFiles
) {
401 std::ostringstream err
;
402 std::string
escaping_conf_1_f(next_tempfile(escaping_conf_1
));
405 ASSERT_EQ(cf1
.parse_file(escaping_conf_1_f
.c_str(), &err
), 0);
406 ASSERT_EQ(err
.tellp(), 0U);
408 ASSERT_EQ(cf1
.read("global", "log file", val
), 0);
409 ASSERT_EQ(val
, "the \"scare quotes\"");
410 ASSERT_EQ(cf1
.read("global", "pid file", val
), 0);
411 ASSERT_EQ(val
, "a pid file");
412 ASSERT_EQ(cf1
.read("mon", "keyring", val
), 0);
413 ASSERT_EQ(val
, "nested \"quotes\"");
415 std::string
escaping_conf_2_f(next_tempfile(escaping_conf_2
));
417 ASSERT_EQ(cf2
.parse_file(escaping_conf_2_f
.c_str(), &err
), 0);
418 ASSERT_EQ(err
.tellp(), 0U);
420 ASSERT_EQ(cf2
.read("apple ][", "log file", val
), 0);
421 ASSERT_EQ(val
, "floppy disk");
422 ASSERT_EQ(cf2
.read("mon", "keyring", val
), 0);
423 ASSERT_EQ(val
, "backslash\\");
426 TEST(ConfUtils
, Overrides
) {
427 ConfigProxy conf
{false};
428 std::ostringstream warn
;
429 std::string
override_conf_1_f(next_tempfile(override_config_1
));
431 conf
->name
.set(CEPH_ENTITY_TYPE_MON
, "0");
432 conf
.parse_config_files(override_conf_1_f
.c_str(), &warn
, 0);
433 ASSERT_FALSE(conf
.has_parse_error());
434 ASSERT_EQ(conf
->log_file
, "global_log");
436 conf
->name
.set(CEPH_ENTITY_TYPE_MDS
, "a");
437 conf
.parse_config_files(override_conf_1_f
.c_str(), &warn
, 0);
438 ASSERT_FALSE(conf
.has_parse_error());
439 ASSERT_EQ(conf
->log_file
, "mds_log");
441 conf
->name
.set(CEPH_ENTITY_TYPE_OSD
, "0");
442 conf
.parse_config_files(override_conf_1_f
.c_str(), &warn
, 0);
443 ASSERT_FALSE(conf
.has_parse_error());
444 ASSERT_EQ(conf
->log_file
, "osd0_log");
447 TEST(ConfUtils
, DupKey
) {
448 ConfigProxy conf
{false};
449 std::ostringstream warn
;
450 std::string
dup_key_config_f(next_tempfile(dup_key_config_1
));
452 conf
->name
.set(CEPH_ENTITY_TYPE_MDS
, "a");
453 conf
.parse_config_files(dup_key_config_f
.c_str(), &warn
, 0);
454 ASSERT_FALSE(conf
.has_parse_error());
455 ASSERT_EQ(conf
->log_file
, string("3"));