diff options
Diffstat (limited to 'src/test/mgr')
-rw-r--r-- | src/test/mgr/CMakeLists.txt | 16 | ||||
-rwxr-xr-x | src/test/mgr/mgr-dashboard-smoke.sh | 78 | ||||
-rw-r--r-- | src/test/mgr/test_mgrcap.cc | 298 |
3 files changed, 392 insertions, 0 deletions
diff --git a/src/test/mgr/CMakeLists.txt b/src/test/mgr/CMakeLists.txt new file mode 100644 index 00000000..9e6950d7 --- /dev/null +++ b/src/test/mgr/CMakeLists.txt @@ -0,0 +1,16 @@ +# unittest_mgr_mgrcap +add_executable(unittest_mgr_mgrcap + test_mgrcap.cc + $<TARGET_OBJECTS:mgr_cap_obj>) +add_ceph_unittest(unittest_mgr_mgrcap) +target_link_libraries(unittest_mgr_mgrcap global) + +#scripts +if(WITH_MGR_DASHBOARD_FRONTEND) + if(NOT CMAKE_SYSTEM_PROCESSOR MATCHES "aarch64|AARCH64|arm|ARM") + add_ceph_test(mgr-dashboard-frontend-unittests ${CMAKE_SOURCE_DIR}/src/pybind/mgr/dashboard/run-frontend-unittests.sh) + endif(NOT CMAKE_SYSTEM_PROCESSOR MATCHES "aarch64|AARCH64|arm|ARM") + + add_ceph_test(mgr-dashboard-smoke.sh ${CMAKE_CURRENT_SOURCE_DIR}/mgr-dashboard-smoke.sh) +endif(WITH_MGR_DASHBOARD_FRONTEND) + diff --git a/src/test/mgr/mgr-dashboard-smoke.sh b/src/test/mgr/mgr-dashboard-smoke.sh new file mode 100755 index 00000000..c3f2a822 --- /dev/null +++ b/src/test/mgr/mgr-dashboard-smoke.sh @@ -0,0 +1,78 @@ +#!/usr/bin/env bash +# +# Copyright (C) 2014,2015,2017 Red Hat <contact@redhat.com> +# Copyright (C) 2018 SUSE LLC +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU Library Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Library Public License for more details. +# +source $(dirname $0)/../detect-build-env-vars.sh +source $CEPH_ROOT/qa/standalone/ceph-helpers.sh + +function run() { + local dir=$1 + shift + + export CEPH_MON=127.0.0.1:7160 # git grep '\<7160\>' : there must be only one + export CEPH_ARGS + CEPH_ARGS+="--fsid=$(uuidgen) --auth-supported=none " + CEPH_ARGS+="--mon-initial-members=a --mon-host=$MON " + CEPH_ARGS+="--mgr-initial-modules=dashboard " + CEPH_ARGS+="--mon-host=$CEPH_MON" + + setup $dir || return 1 + TEST_dashboard $dir || return 1 + teardown $dir || return 1 +} + +function TEST_dashboard() { + local dir=$1 + shift + + run_mon $dir a || return 1 + timeout 30 ceph mon stat || return 1 + ceph config-key set mgr/dashboard/x/server_port 7161 + MGR_ARGS+="--mgr_module_path=${CEPH_ROOT}/src/pybind/mgr " + run_mgr $dir x ${MGR_ARGS} || return 1 + + tries=0 + while [[ $tries < 30 ]] ; do + if [ $(ceph status -f json | jq .mgrmap.available) = "true" ] + then + break + fi + tries=$((tries+1)) + sleep 1 + done + + DASHBOARD_ADMIN_SECRET_FILE="/tmp/dashboard-admin-secret.txt" + printf 'admin' > "${DASHBOARD_ADMIN_SECRET_FILE}" + ceph_adm tell mgr dashboard ac-user-create admin -i "${DASHBOARD_ADMIN_SECRET_FILE}" + + tries=0 + while [[ $tries < 30 ]] ; do + if curl -c $dir/cookiefile -X POST -d '{"username":"admin","password":"admin"}' http://127.0.0.1:7161/api/auth + then + if curl -b $dir/cookiefile -s http://127.0.0.1:7161/api/summary | \ + jq '.health.overall_status' | grep HEALTH_ + then + break + fi + fi + tries=$((tries+1)) + sleep 0.5 + done +} + +main mgr-dashboard-smoke "$@" + +# Local Variables: +# compile-command: "cd ../.. ; make -j4 TESTS=test/mgr/mgr-dashboard-smoke.sh check" +# End: diff --git a/src/test/mgr/test_mgrcap.cc b/src/test/mgr/test_mgrcap.cc new file mode 100644 index 00000000..90933dd7 --- /dev/null +++ b/src/test/mgr/test_mgrcap.cc @@ -0,0 +1,298 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab +/* + * Ceph - scalable distributed file system + * + * Copyright (C) 2012 Inktank + * + * This is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software + * Foundation. See file COPYING. + * + */ + +#include <iostream> + +#include "include/stringify.h" +#include "mgr/MgrCap.h" + +#include "gtest/gtest.h" + +const char *parse_good[] = { + + // MgrCapMatch + "allow *", + "allow r", + "allow rwx", + "allow r", + " allow rwx", + "allow rwx ", + " allow rwx ", + " allow\t rwx ", + "\tallow\nrwx\t", + "allow service=foo x", + "allow service=\"froo\" x", + "allow profile read-only", + "allow profile read-write", + "allow profile \"rbd-read-only\", allow *", + "allow command \"a b c\"", + "allow command abc", + "allow command abc with arg=foo", + "allow command abc with arg=foo arg2=bar", + "allow command abc with arg=foo arg2=bar", + "allow command abc with arg=foo arg2 prefix bar arg3 prefix baz", + "allow command abc with arg=foo arg2 prefix \"bar bingo\" arg3 prefix baz", + "allow command abc with arg regex \"^[0-9a-z.]*$\"", + "allow command abc with arg regex \"\(invaluid regex\"", + "allow service foo x", + "allow service foo x; allow service bar x", + "allow service foo w ;allow service bar x", + "allow service foo w , allow service bar x", + "allow service foo r , allow service bar x", + "allow service foo_foo r, allow service bar r", + "allow service foo-foo r, allow service bar r", + "allow service \" foo \" w, allow service bar r", + "allow module foo x", + "allow module=foo x", + "allow module foo_foo r", + "allow module \" foo \" w", + "allow module foo with arg1=value1 x", + "allow command abc with arg=foo arg2=bar, allow service foo r", + "allow command abc.def with arg=foo arg2=bar, allow service foo r", + "allow command \"foo bar\" with arg=\"baz\"", + "allow command \"foo bar\" with arg=\"baz.xx\"", + "allow command \"foo bar\" with arg = \"baz.xx\"", + "profile crash", + "profile osd", + "profile mds", + "profile rbd pool=ABC namespace=NS", + "profile \"rbd-read-only\", profile crash", + "allow * network 1.2.3.4/24", + "allow * network ::1/128", + "allow * network [aa:bb::1]/128", + "allow service=foo x network 1.2.3.4/16", + "allow command abc network 1.2.3.4/8", + "profile crash network 1.2.3.4/32", + "allow profile crash network 1.2.3.4/32", + 0 +}; + +TEST(MgrCap, ParseGood) { + for (int i=0; parse_good[i]; ++i) { + string str = parse_good[i]; + MgrCap cap; + std::cout << "Testing good input: '" << str << "'" << std::endl; + ASSERT_TRUE(cap.parse(str, &cout)); + std::cout << " -> " << cap + << std::endl; + } +} + +// these should stringify to the input value +const char *parse_identity[] = { + "allow *", + "allow r", + "allow rwx", + "allow service foo x", + "profile crash", + "profile rbd-read-only, allow *", + "profile rbd namespace=NS pool=ABC", + "allow command abc", + "allow command \"a b c\"", + "allow command abc with arg=foo", + "allow command abc with arg=foo arg2=bar", + "allow command abc with arg=foo arg2=bar", + "allow command abc with arg=foo arg2 prefix bar arg3 prefix baz", + "allow command abc with arg=foo arg2 prefix \"bar bingo\" arg3 prefix baz", + "allow service foo x", + "allow service foo x, allow service bar x", + "allow service foo w, allow service bar x", + "allow service foo r, allow service bar x", + "allow service foo_foo r, allow service bar r", + "allow service foo-foo r, allow service bar r", + "allow service \" foo \" w, allow service bar r", + "allow module foo x", + "allow module \" foo_foo \" r", + "allow module foo with arg1=value1 x", + "allow command abc with arg=foo arg2=bar, allow service foo r", + 0 +}; + +TEST(MgrCap, ParseIdentity) +{ + for (int i=0; parse_identity[i]; ++i) { + string str = parse_identity[i]; + MgrCap cap; + std::cout << "Testing good input: '" << str << "'" << std::endl; + ASSERT_TRUE(cap.parse(str, &cout)); + string out = stringify(cap); + ASSERT_EQ(out, str); + } +} + +const char *parse_bad[] = { + "allow r foo", + "allow*", + "foo allow *", + "profile foo rwx", + "profile", + "profile foo bar rwx", + "allow profile foo rwx", + "allow profile", + "allow profile foo bar rwx", + "allow service bar", + "allow command baz x", + "allow r w", + "ALLOW r", + "allow rwx,", + "allow rwx x", + "allow r pool foo r", + "allow wwx pool taco", + "allow wwx pool taco^funny&chars", + "allow rwx pool 'weird name''", + "allow rwx object_prefix \"beforepool\" pool weird", + "allow rwx auid 123 pool asdf", + "allow command foo a prefix b", + "allow command foo with a prefixb", + "allow command foo with a = prefix b", + "allow command foo with a prefix b c", + 0 +}; + +TEST(MgrCap, ParseBad) { + for (int i=0; parse_bad[i]; ++i) { + string str = parse_bad[i]; + MgrCap cap; + std::cout << "Testing bad input: '" << str << "'" << std::endl; + ASSERT_FALSE(cap.parse(str, &cout)); + } +} + +TEST(MgrCap, AllowAll) { + MgrCap cap; + ASSERT_FALSE(cap.is_allow_all()); + + ASSERT_TRUE(cap.parse("allow r", nullptr)); + ASSERT_FALSE(cap.is_allow_all()); + cap.grants.clear(); + + ASSERT_TRUE(cap.parse("allow w", nullptr)); + ASSERT_FALSE(cap.is_allow_all()); + cap.grants.clear(); + + ASSERT_TRUE(cap.parse("allow x", nullptr)); + ASSERT_FALSE(cap.is_allow_all()); + cap.grants.clear(); + + ASSERT_TRUE(cap.parse("allow rwx", nullptr)); + ASSERT_FALSE(cap.is_allow_all()); + cap.grants.clear(); + + ASSERT_TRUE(cap.parse("allow rw", nullptr)); + ASSERT_FALSE(cap.is_allow_all()); + cap.grants.clear(); + + ASSERT_TRUE(cap.parse("allow rx", nullptr)); + ASSERT_FALSE(cap.is_allow_all()); + cap.grants.clear(); + + ASSERT_TRUE(cap.parse("allow wx", nullptr)); + ASSERT_FALSE(cap.is_allow_all()); + cap.grants.clear(); + + ASSERT_TRUE(cap.parse("allow *", nullptr)); + ASSERT_TRUE(cap.is_allow_all()); + ASSERT_TRUE(cap.is_capable(nullptr, {}, "foo", "", "asdf", {}, true, true, + true, {})); + + MgrCap cap2; + ASSERT_FALSE(cap2.is_allow_all()); + cap2.set_allow_all(); + ASSERT_TRUE(cap2.is_allow_all()); +} + +TEST(MgrCap, Network) { + MgrCap cap; + bool r = cap.parse("allow * network 192.168.0.0/16, allow * network 10.0.0.0/8", nullptr); + ASSERT_TRUE(r); + + entity_addr_t a, b, c; + a.parse("10.1.2.3"); + b.parse("192.168.2.3"); + c.parse("192.167.2.3"); + + ASSERT_TRUE(cap.is_capable(nullptr, {}, "foo", "", "asdf", {}, true, true, + true, a)); + ASSERT_TRUE(cap.is_capable(nullptr, {}, "foo", "", "asdf", {}, true, true, + true, b)); + ASSERT_FALSE(cap.is_capable(nullptr, {}, "foo", "", "asdf", {}, true, true, + true, c)); +} + +TEST(MgrCap, CommandRegEx) { + MgrCap cap; + ASSERT_FALSE(cap.is_allow_all()); + ASSERT_TRUE(cap.parse("allow command abc with arg regex \"^[0-9a-z.]*$\"", + nullptr)); + + EntityName name; + name.from_str("osd.123"); + ASSERT_TRUE(cap.is_capable(nullptr, name, "", "", "abc", + {{"arg", "12345abcde"}}, true, true, true, {})); + ASSERT_FALSE(cap.is_capable(nullptr, name, "", "", "abc", {{"arg", "~!@#$"}}, + true, true, true, {})); + + ASSERT_TRUE(cap.parse("allow command abc with arg regex \"[*\"", nullptr)); + ASSERT_FALSE(cap.is_capable(nullptr, name, "", "", "abc", {{"arg", ""}}, true, + true, true, {})); +} + +TEST(MgrCap, Module) { + MgrCap cap; + ASSERT_FALSE(cap.is_allow_all()); + ASSERT_TRUE(cap.parse("allow module abc r, allow module bcd w", nullptr)); + + ASSERT_FALSE(cap.is_capable(nullptr, {}, "", "abc", "", {}, true, true, false, + {})); + ASSERT_TRUE(cap.is_capable(nullptr, {}, "", "abc", "", {}, true, false, false, + {})); + ASSERT_FALSE(cap.is_capable(nullptr, {}, "", "bcd", "", {}, true, true, false, + {})); + ASSERT_TRUE(cap.is_capable(nullptr, {}, "", "bcd", "", {}, false, true, false, + {})); +} + +TEST(MgrCap, Profile) { + MgrCap cap; + ASSERT_FALSE(cap.is_allow_all()); + + ASSERT_FALSE(cap.parse("profile unknown")); + ASSERT_FALSE(cap.parse("profile rbd invalid-key=value")); + + ASSERT_TRUE(cap.parse("profile rbd", nullptr)); + ASSERT_FALSE(cap.is_capable(nullptr, {}, "", "abc", "", {}, true, false, + false, {})); + ASSERT_TRUE(cap.is_capable(nullptr, {}, "", "rbd_support", "", {}, true, + true, false, {})); + ASSERT_TRUE(cap.is_capable(nullptr, {}, "", "rbd_support", "", {}, true, + false, false, {})); + + ASSERT_TRUE(cap.parse("profile rbd pool=abc namespace prefix def", nullptr)); + ASSERT_FALSE(cap.is_capable(nullptr, {}, "", "rbd_support", "", {}, + true, true, false, {})); + ASSERT_FALSE(cap.is_capable(nullptr, {}, "", "rbd_support", "", + {{"pool", "abc"}}, + true, true, false, {})); + ASSERT_TRUE(cap.is_capable(nullptr, {}, "", "rbd_support", "", + {{"pool", "abc"}, {"namespace", "defghi"}}, + true, true, false, {})); + + ASSERT_TRUE(cap.parse("profile rbd-read-only", nullptr)); + ASSERT_FALSE(cap.is_capable(nullptr, {}, "", "abc", "", {}, true, false, + false, {})); + ASSERT_FALSE(cap.is_capable(nullptr, {}, "", "rbd_support", "", {}, true, + true, false, {})); + ASSERT_TRUE(cap.is_capable(nullptr, {}, "", "rbd_support", "", {}, true, + false, false, {})); +} |