utils.bash 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558
  1. #!/bin/bash
  2. # This file contains some utilities to test the elasticsearch scripts,
  3. # the .deb/.rpm packages and the SysV/Systemd scripts.
  4. # WARNING: This testing file must be executed as root and can
  5. # dramatically change your system. It removes the 'elasticsearch'
  6. # user/group and also many directories. Do not execute this file
  7. # unless you know exactly what you are doing.
  8. # Licensed to Elasticsearch under one or more contributor
  9. # license agreements. See the NOTICE file distributed with
  10. # this work for additional information regarding copyright
  11. # ownership. Elasticsearch licenses this file to you under
  12. # the Apache License, Version 2.0 (the "License"); you may
  13. # not use this file except in compliance with the License.
  14. # You may obtain a copy of the License at
  15. #
  16. # http://www.apache.org/licenses/LICENSE-2.0
  17. #
  18. # Unless required by applicable law or agreed to in writing,
  19. # software distributed under the License is distributed on an
  20. # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  21. # KIND, either express or implied. See the License for the
  22. # specific language governing permissions and limitations
  23. # under the License.
  24. # Checks if necessary commands are available to run the tests
  25. if [ ! -x /usr/bin/which ]; then
  26. echo "'which' command is mandatory to run the tests"
  27. exit 1
  28. fi
  29. if [ ! -x "`which wget 2>/dev/null`" ]; then
  30. echo "'wget' command is mandatory to run the tests"
  31. exit 1
  32. fi
  33. if [ ! -x "`which curl 2>/dev/null`" ]; then
  34. echo "'curl' command is mandatory to run the tests"
  35. exit 1
  36. fi
  37. if [ ! -x "`which pgrep 2>/dev/null`" ]; then
  38. echo "'pgrep' command is mandatory to run the tests"
  39. exit 1
  40. fi
  41. if [ ! -x "`which unzip 2>/dev/null`" ]; then
  42. echo "'unzip' command is mandatory to run the tests"
  43. exit 1
  44. fi
  45. if [ ! -x "`which tar 2>/dev/null`" ]; then
  46. echo "'tar' command is mandatory to run the tests"
  47. exit 1
  48. fi
  49. if [ ! -x "`which unzip 2>/dev/null`" ]; then
  50. echo "'unzip' command is mandatory to run the tests"
  51. exit 1
  52. fi
  53. if [ ! -x "`which java 2>/dev/null`" ]; then
  54. echo "'java' command is mandatory to run the tests"
  55. exit 1
  56. fi
  57. # Returns 0 if the 'dpkg' command is available
  58. is_dpkg() {
  59. [ -x "`which dpkg 2>/dev/null`" ]
  60. }
  61. # Returns 0 if the 'rpm' command is available
  62. is_rpm() {
  63. [ -x "`which rpm 2>/dev/null`" ]
  64. }
  65. # Skip test if the 'dpkg' command is not supported
  66. skip_not_dpkg() {
  67. is_dpkg || skip "dpkg is not supported"
  68. }
  69. # Skip test if the 'rpm' command is not supported
  70. skip_not_rpm() {
  71. is_rpm || skip "rpm is not supported"
  72. }
  73. skip_not_dpkg_or_rpm() {
  74. is_dpkg || is_rpm || skip "only dpkg or rpm systems are supported"
  75. }
  76. # Returns 0 if the system supports Systemd
  77. is_systemd() {
  78. [ -x /bin/systemctl ]
  79. }
  80. # Skip test if Systemd is not supported
  81. skip_not_systemd() {
  82. if [ ! -x /bin/systemctl ]; then
  83. skip "systemd is not supported"
  84. fi
  85. }
  86. # Returns 0 if the system supports SysV
  87. is_sysvinit() {
  88. [ -x "`which service 2>/dev/null`" ]
  89. }
  90. # Skip test if SysV is not supported
  91. skip_not_sysvinit() {
  92. if [ -x "`which service 2>/dev/null`" ] && is_systemd; then
  93. skip "sysvinit is supported, but systemd too"
  94. fi
  95. if [ ! -x "`which service 2>/dev/null`" ]; then
  96. skip "sysvinit is not supported"
  97. fi
  98. }
  99. # Skip if tar is not supported
  100. skip_not_tar_gz() {
  101. if [ ! -x "`which tar 2>/dev/null`" ]; then
  102. skip "tar is not supported"
  103. fi
  104. }
  105. # Skip if unzip is not supported
  106. skip_not_zip() {
  107. if [ ! -x "`which unzip 2>/dev/null`" ]; then
  108. skip "unzip is not supported"
  109. fi
  110. }
  111. assert_file_exist() {
  112. local file="$1"
  113. if [ ! -e "$file" ]; then
  114. echo "Should exist: ${file} but does not"
  115. fi
  116. local file=$(readlink -m "${file}")
  117. [ -e "$file" ]
  118. }
  119. assert_file_not_exist() {
  120. local file="$1"
  121. if [ -e "$file" ]; then
  122. echo "Should not exist: ${file} but does"
  123. fi
  124. local file=$(readlink -m "${file}")
  125. [ ! -e "$file" ]
  126. }
  127. assert_file() {
  128. local file="$1"
  129. local type=$2
  130. local user=$3
  131. local group=$4
  132. local privileges=$5
  133. assert_file_exist "$file"
  134. if [ "$type" = "d" ]; then
  135. if [ ! -d "$file" ]; then
  136. echo "[$file] should be a directory but is not"
  137. fi
  138. [ -d "$file" ]
  139. else
  140. if [ ! -f "$file" ]; then
  141. echo "[$file] should be a regular file but is not"
  142. fi
  143. [ -f "$file" ]
  144. fi
  145. if [ "x$user" != "x" ]; then
  146. realuser=$(find "$file" -maxdepth 0 -printf "%u")
  147. if [ "$realuser" != "$user" ]; then
  148. echo "Expected user: $user, found $realuser [$file]"
  149. fi
  150. [ "$realuser" = "$user" ]
  151. fi
  152. if [ "x$group" != "x" ]; then
  153. realgroup=$(find "$file" -maxdepth 0 -printf "%g")
  154. if [ "$realgroup" != "$group" ]; then
  155. echo "Expected group: $group, found $realgroup [$file]"
  156. fi
  157. [ "$realgroup" = "$group" ]
  158. fi
  159. if [ "x$privileges" != "x" ]; then
  160. realprivileges=$(find "$file" -maxdepth 0 -printf "%m")
  161. if [ "$realprivileges" != "$privileges" ]; then
  162. echo "Expected privileges: $privileges, found $realprivileges [$file]"
  163. fi
  164. [ "$realprivileges" = "$privileges" ]
  165. fi
  166. }
  167. assert_module_or_plugin_directory() {
  168. local directory=$1
  169. shift
  170. #owner group and permissions vary depending on how es was installed
  171. #just make sure that everything is the same as $CONFIG_DIR, which was properly set up during install
  172. config_user=$(find "$ESHOME" -maxdepth 0 -printf "%u")
  173. config_owner=$(find "$ESHOME" -maxdepth 0 -printf "%g")
  174. assert_file $directory d $config_user $config_owner 755
  175. }
  176. assert_module_or_plugin_file() {
  177. local file=$1
  178. shift
  179. assert_file_exist "$(readlink -m $file)"
  180. assert_file $file f $config_user $config_owner 644
  181. }
  182. assert_output() {
  183. echo "$output" | grep -E "$1"
  184. }
  185. assert_recursive_ownership() {
  186. local directory=$1
  187. local user=$2
  188. local group=$3
  189. realuser=$(find $directory -printf "%u\n" | sort | uniq)
  190. [ "$realuser" = "$user" ]
  191. realgroup=$(find $directory -printf "%g\n" | sort | uniq)
  192. [ "$realgroup" = "$group" ]
  193. }
  194. # Deletes everything before running a test file
  195. clean_before_test() {
  196. # List of files to be deleted
  197. ELASTICSEARCH_TEST_FILES=("/usr/share/elasticsearch" \
  198. "/etc/elasticsearch" \
  199. "/var/lib/elasticsearch" \
  200. "/var/log/elasticsearch" \
  201. "/tmp/elasticsearch" \
  202. "/etc/default/elasticsearch" \
  203. "/etc/sysconfig/elasticsearch" \
  204. "/var/run/elasticsearch" \
  205. "/usr/share/doc/elasticsearch" \
  206. "/tmp/elasticsearch" \
  207. "/usr/lib/systemd/system/elasticsearch.conf" \
  208. "/usr/lib/tmpfiles.d/elasticsearch.conf" \
  209. "/usr/lib/sysctl.d/elasticsearch.conf")
  210. # Kills all processes of user elasticsearch
  211. if id elasticsearch > /dev/null 2>&1; then
  212. pkill -u elasticsearch 2>/dev/null || true
  213. fi
  214. # Kills all running Elasticsearch processes
  215. ps aux | grep -i "org.elasticsearch.bootstrap.Elasticsearch" | awk {'print $2'} | xargs kill -9 > /dev/null 2>&1 || true
  216. purge_elasticsearch
  217. # Removes user & group
  218. userdel elasticsearch > /dev/null 2>&1 || true
  219. groupdel elasticsearch > /dev/null 2>&1 || true
  220. # Removes all files
  221. for d in "${ELASTICSEARCH_TEST_FILES[@]}"; do
  222. if [ -e "$d" ]; then
  223. rm -rf "$d"
  224. fi
  225. done
  226. }
  227. purge_elasticsearch() {
  228. # Removes RPM package
  229. if is_rpm; then
  230. rpm --quiet -e elasticsearch > /dev/null 2>&1 || true
  231. fi
  232. if [ -x "`which yum 2>/dev/null`" ]; then
  233. yum remove -y elasticsearch > /dev/null 2>&1 || true
  234. fi
  235. # Removes DEB package
  236. if is_dpkg; then
  237. dpkg --purge elasticsearch > /dev/null 2>&1 || true
  238. fi
  239. if [ -x "`which apt-get 2>/dev/null`" ]; then
  240. apt-get --quiet --yes purge elasticsearch > /dev/null 2>&1 || true
  241. fi
  242. }
  243. # Start elasticsearch and wait for it to come up with a status.
  244. # $1 - expected status - defaults to green
  245. start_elasticsearch_service() {
  246. local desiredStatus=${1:-green}
  247. local index=$2
  248. local commandLineArgs=$3
  249. run_elasticsearch_service 0 $commandLineArgs
  250. wait_for_elasticsearch_status $desiredStatus $index
  251. if [ -r "/tmp/elasticsearch/elasticsearch.pid" ]; then
  252. pid=$(cat /tmp/elasticsearch/elasticsearch.pid)
  253. [ "x$pid" != "x" ] && [ "$pid" -gt 0 ]
  254. echo "Looking for elasticsearch pid...."
  255. ps $pid
  256. elif is_systemd; then
  257. run systemctl is-active elasticsearch.service
  258. [ "$status" -eq 0 ]
  259. run systemctl status elasticsearch.service
  260. [ "$status" -eq 0 ]
  261. elif is_sysvinit; then
  262. run service elasticsearch status
  263. [ "$status" -eq 0 ]
  264. fi
  265. }
  266. # Start elasticsearch
  267. # $1 expected status code
  268. # $2 additional command line args
  269. run_elasticsearch_service() {
  270. local expectedStatus=$1
  271. local commandLineArgs=$2
  272. # Set the CONF_DIR setting in case we start as a service
  273. if [ ! -z "$CONF_DIR" ] ; then
  274. if is_dpkg ; then
  275. echo "CONF_DIR=$CONF_DIR" >> /etc/default/elasticsearch;
  276. echo "ES_JVM_OPTIONS=$ES_JVM_OPTIONS" >> /etc/default/elasticsearch;
  277. elif is_rpm; then
  278. echo "CONF_DIR=$CONF_DIR" >> /etc/sysconfig/elasticsearch;
  279. echo "ES_JVM_OPTIONS=$ES_JVM_OPTIONS" >> /etc/sysconfig/elasticsearch
  280. fi
  281. fi
  282. if [ -f "/tmp/elasticsearch/bin/elasticsearch" ]; then
  283. if [ -z "$CONF_DIR" ]; then
  284. local CONF_DIR=""
  285. local ES_PATH_CONF=""
  286. else
  287. local ES_PATH_CONF="-Epath.conf=$CONF_DIR"
  288. fi
  289. # we must capture the exit code to compare so we don't want to start as background process in case we expect something other than 0
  290. local background=""
  291. local timeoutCommand=""
  292. if [ "$expectedStatus" = 0 ]; then
  293. background="-d"
  294. else
  295. timeoutCommand="timeout 60s "
  296. fi
  297. # su and the Elasticsearch init script work together to break bats.
  298. # sudo isolates bats enough from the init script so everything continues
  299. # to tick along
  300. run sudo -u elasticsearch bash <<BASH
  301. # If jayatana is installed then we try to use it. Elasticsearch should ignore it even when we try.
  302. # If it doesn't ignore it then Elasticsearch will fail to start because of security errors.
  303. # This line is attempting to emulate the on login behavior of /usr/share/upstart/sessions/jayatana.conf
  304. [ -f /usr/share/java/jayatanaag.jar ] && export JAVA_TOOL_OPTIONS="-javaagent:/usr/share/java/jayatanaag.jar"
  305. # And now we can start Elasticsearch normally, in the background (-d) and with a pidfile (-p).
  306. export ES_JVM_OPTIONS=$ES_JVM_OPTIONS
  307. export ES_JAVA_OPTS=$ES_JAVA_OPTS
  308. $timeoutCommand/tmp/elasticsearch/bin/elasticsearch $background -p /tmp/elasticsearch/elasticsearch.pid $ES_PATH_CONF $commandLineArgs
  309. BASH
  310. [ "$status" -eq "$expectedStatus" ]
  311. elif is_systemd; then
  312. run systemctl daemon-reload
  313. [ "$status" -eq 0 ]
  314. run systemctl enable elasticsearch.service
  315. [ "$status" -eq 0 ]
  316. run systemctl is-enabled elasticsearch.service
  317. [ "$status" -eq 0 ]
  318. run systemctl start elasticsearch.service
  319. [ "$status" -eq "$expectedStatus" ]
  320. elif is_sysvinit; then
  321. run service elasticsearch start
  322. [ "$status" -eq "$expectedStatus" ]
  323. fi
  324. }
  325. stop_elasticsearch_service() {
  326. if [ -r "/tmp/elasticsearch/elasticsearch.pid" ]; then
  327. pid=$(cat /tmp/elasticsearch/elasticsearch.pid)
  328. [ "x$pid" != "x" ] && [ "$pid" -gt 0 ]
  329. kill -SIGTERM $pid
  330. elif is_systemd; then
  331. run systemctl stop elasticsearch.service
  332. [ "$status" -eq 0 ]
  333. run systemctl is-active elasticsearch.service
  334. [ "$status" -eq 3 ]
  335. echo "$output" | grep -E 'inactive|failed'
  336. elif is_sysvinit; then
  337. run service elasticsearch stop
  338. [ "$status" -eq 0 ]
  339. run service elasticsearch status
  340. [ "$status" -ne 0 ]
  341. fi
  342. }
  343. # Waits for Elasticsearch to reach some status.
  344. # $1 - expected status - defaults to green
  345. wait_for_elasticsearch_status() {
  346. local desiredStatus=${1:-green}
  347. local index=$2
  348. echo "Making sure elasticsearch is up..."
  349. wget -O - --retry-connrefused --waitretry=1 --timeout=60 --tries 60 http://localhost:9200/_cluster/health || {
  350. echo "Looks like elasticsearch never started. Here is its log:"
  351. if [ -e "$ESLOG/elasticsearch.log" ]; then
  352. cat "$ESLOG/elasticsearch.log"
  353. else
  354. echo "The elasticsearch log doesn't exist. Maybe /var/log/messages has something:"
  355. tail -n20 /var/log/messages
  356. fi
  357. false
  358. }
  359. if [ -z "index" ]; then
  360. echo "Tring to connect to elasticsearch and wait for expected status $desiredStatus..."
  361. curl -sS "http://localhost:9200/_cluster/health?wait_for_status=$desiredStatus&timeout=60s&pretty"
  362. else
  363. echo "Trying to connect to elasticsearch and wait for expected status $desiredStatus for index $index"
  364. curl -sS "http://localhost:9200/_cluster/health/$index?wait_for_status=$desiredStatus&timeout=60s&pretty"
  365. fi
  366. if [ $? -eq 0 ]; then
  367. echo "Connected"
  368. else
  369. echo "Unable to connect to Elasticsearch"
  370. false
  371. fi
  372. echo "Checking that the cluster health matches the waited for status..."
  373. run curl -sS -XGET 'http://localhost:9200/_cat/health?h=status&v=false'
  374. if [ "$status" -ne 0 ]; then
  375. echo "error when checking cluster health. code=$status output="
  376. echo $output
  377. false
  378. fi
  379. echo $output | grep $desiredStatus || {
  380. echo "unexpected status: '$output' wanted '$desiredStatus'"
  381. false
  382. }
  383. }
  384. # Checks the current elasticsearch version using the Info REST endpoint
  385. # $1 - expected version
  386. check_elasticsearch_version() {
  387. local version=$1
  388. local versionToCheck=$(echo $version | sed -e 's/-SNAPSHOT//')
  389. run curl -s localhost:9200
  390. [ "$status" -eq 0 ]
  391. echo $output | grep \"number\"\ :\ \"$versionToCheck\" || {
  392. echo "Installed an unexpected version:"
  393. curl -s localhost:9200
  394. false
  395. }
  396. }
  397. install_elasticsearch_test_scripts() {
  398. install_script is_guide.painless
  399. install_script is_guide.mustache
  400. }
  401. # Executes some basic Elasticsearch tests
  402. run_elasticsearch_tests() {
  403. # TODO this assertion is the same the one made when waiting for
  404. # elasticsearch to start
  405. run curl -XGET 'http://localhost:9200/_cat/health?h=status&v=false'
  406. [ "$status" -eq 0 ]
  407. echo "$output" | grep -w "green"
  408. curl -s -H "Content-Type: application/json" -XPOST 'http://localhost:9200/library/book/1?refresh=true&pretty' -d '{
  409. "title": "Book #1",
  410. "pages": 123
  411. }'
  412. curl -s -H "Content-Type: application/json" -XPOST 'http://localhost:9200/library/book/2?refresh=true&pretty' -d '{
  413. "title": "Book #2",
  414. "pages": 456
  415. }'
  416. curl -s -XGET 'http://localhost:9200/_count?pretty' |
  417. grep \"count\"\ :\ 2
  418. curl -s -H "Content-Type: application/json" -XPOST 'http://localhost:9200/library/book/_count?pretty' -d '{
  419. "query": {
  420. "script": {
  421. "script": {
  422. "file": "is_guide",
  423. "lang": "painless",
  424. "params": {
  425. "min_num_pages": 100
  426. }
  427. }
  428. }
  429. }
  430. }' | grep \"count\"\ :\ 2
  431. curl -s -H "Content-Type: application/json" -XGET 'http://localhost:9200/library/book/_search/template?pretty' -d '{
  432. "file": "is_guide"
  433. }' | grep \"total\"\ :\ 1
  434. curl -s -XDELETE 'http://localhost:9200/_all'
  435. }
  436. # Move the config directory to another directory and properly chown it.
  437. move_config() {
  438. local oldConfig="$ESCONFIG"
  439. export ESCONFIG="${1:-$(mktemp -d -t 'config.XXXX')}"
  440. echo "Moving configuration directory from $oldConfig to $ESCONFIG"
  441. # Move configuration files to the new configuration directory
  442. mv "$oldConfig"/* "$ESCONFIG"
  443. chown -R elasticsearch:elasticsearch "$ESCONFIG"
  444. assert_file_exist "$ESCONFIG/elasticsearch.yml"
  445. assert_file_exist "$ESCONFIG/jvm.options"
  446. assert_file_exist "$ESCONFIG/log4j2.properties"
  447. }
  448. # Copies a script into the Elasticsearch install.
  449. install_script() {
  450. local name=$1
  451. mkdir -p $ESSCRIPTS
  452. local script="$BATS_TEST_DIRNAME/example/scripts/$name"
  453. echo "Installing $script to $ESSCRIPTS"
  454. cp $script $ESSCRIPTS
  455. }
  456. # permissions from the user umask with the executable bit set
  457. executable_privileges_for_user_from_umask() {
  458. local user=$1
  459. shift
  460. echo $((0777 & ~$(sudo -E -u $user sh -c umask) | 0111))
  461. }
  462. # permissions from the user umask without the executable bit set
  463. file_privileges_for_user_from_umask() {
  464. local user=$1
  465. shift
  466. echo $((0777 & ~$(sudo -E -u $user sh -c umask) & ~0111))
  467. }