utils.bash 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595
  1. #!/bin/bash
  2. # This file contains some utilities to test the .deb/.rpm
  3. # packages and the SysV/Systemd scripts.
  4. # WARNING: This testing file must be executed as root and can
  5. # dramatically change your system. It should only be executed
  6. # in a throw-away VM like those made by the Vagrantfile at
  7. # the root of the Elasticsearch source code. This should
  8. # cause the script to fail if it is executed any other way:
  9. [ -f /etc/is_vagrant_vm ] || {
  10. >&2 echo "must be run on a vagrant VM"
  11. exit 1
  12. }
  13. # Licensed to Elasticsearch under one or more contributor
  14. # license agreements. See the NOTICE file distributed with
  15. # this work for additional information regarding copyright
  16. # ownership. Elasticsearch licenses this file to you under
  17. # the Apache License, Version 2.0 (the "License"); you may
  18. # not use this file except in compliance with the License.
  19. # You may obtain a copy of the License at
  20. #
  21. # http://www.apache.org/licenses/LICENSE-2.0
  22. #
  23. # Unless required by applicable law or agreed to in writing,
  24. # software distributed under the License is distributed on an
  25. # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  26. # KIND, either express or implied. See the License for the
  27. # specific language governing permissions and limitations
  28. # under the License.
  29. # Checks if necessary commands are available to run the tests
  30. if [ ! -x /usr/bin/which ]; then
  31. echo "'which' command is mandatory to run the tests"
  32. exit 1
  33. fi
  34. if [ ! -x "`which wget 2>/dev/null`" ]; then
  35. echo "'wget' command is mandatory to run the tests"
  36. exit 1
  37. fi
  38. if [ ! -x "`which curl 2>/dev/null`" ]; then
  39. echo "'curl' command is mandatory to run the tests"
  40. exit 1
  41. fi
  42. if [ ! -x "`which pgrep 2>/dev/null`" ]; then
  43. echo "'pgrep' command is mandatory to run the tests"
  44. exit 1
  45. fi
  46. if [ ! -x "`which unzip 2>/dev/null`" ]; then
  47. echo "'unzip' command is mandatory to run the tests"
  48. exit 1
  49. fi
  50. if [ ! -x "`which tar 2>/dev/null`" ]; then
  51. echo "'tar' command is mandatory to run the tests"
  52. exit 1
  53. fi
  54. if [ ! -x "`which unzip 2>/dev/null`" ]; then
  55. echo "'unzip' command is mandatory to run the tests"
  56. exit 1
  57. fi
  58. if [ ! -x "$SYSTEM_JAVA_HOME"/bin/java ]; then
  59. # there are some tests that move java temporarily
  60. if [ ! -x "`command -v java.bak 2>/dev/null`" ]; then
  61. echo "'java' command is mandatory to run the tests"
  62. exit 1
  63. fi
  64. fi
  65. # Returns 0 if the 'dpkg' command is available
  66. is_dpkg() {
  67. [ -x "`which dpkg 2>/dev/null`" ]
  68. }
  69. # Returns 0 if the 'rpm' command is available
  70. is_rpm() {
  71. [ -x "`which rpm 2>/dev/null`" ]
  72. }
  73. # Skip test if the 'dpkg' command is not supported
  74. skip_not_dpkg() {
  75. is_dpkg || skip "dpkg is not supported"
  76. }
  77. # Skip test if the 'rpm' command is not supported
  78. skip_not_rpm() {
  79. is_rpm || skip "rpm is not supported"
  80. }
  81. skip_not_dpkg_or_rpm() {
  82. is_dpkg || is_rpm || skip "only dpkg or rpm systems are supported"
  83. }
  84. # Returns 0 if the system supports Systemd
  85. is_systemd() {
  86. [ -x /bin/systemctl ]
  87. }
  88. # Skip test if Systemd is not supported
  89. skip_not_systemd() {
  90. if [ ! -x /bin/systemctl ]; then
  91. skip "systemd is not supported"
  92. fi
  93. }
  94. # Returns 0 if the system supports SysV
  95. is_sysvinit() {
  96. [ -x "`which service 2>/dev/null`" ]
  97. }
  98. # Skip test if SysV is not supported
  99. skip_not_sysvinit() {
  100. if [ -x "`which service 2>/dev/null`" ] && is_systemd; then
  101. skip "sysvinit is supported, but systemd too"
  102. fi
  103. if [ ! -x "`which service 2>/dev/null`" ]; then
  104. skip "sysvinit is not supported"
  105. fi
  106. }
  107. # Skip if tar is not supported
  108. skip_not_tar_gz() {
  109. if [ ! -x "`which tar 2>/dev/null`" ]; then
  110. skip "tar is not supported"
  111. fi
  112. }
  113. # Skip if unzip is not supported
  114. skip_not_zip() {
  115. if [ ! -x "`which unzip 2>/dev/null`" ]; then
  116. skip "unzip is not supported"
  117. fi
  118. }
  119. assert_file_exist() {
  120. local file="$1"
  121. local count=$(echo "$file" | wc -l)
  122. [[ "$count" == "1" ]] || {
  123. echo "assert_file_exist must be run on a single file at a time but was called on [$count] files: $file"
  124. false
  125. }
  126. if [ ! -e "$file" ]; then
  127. echo "Should exist: ${file} but does not"
  128. fi
  129. local file=$(readlink -m "${file}")
  130. [ -e "$file" ]
  131. }
  132. assert_file_not_exist() {
  133. local file="$1"
  134. if [ -e "$file" ]; then
  135. echo "Should not exist: ${file} but does"
  136. fi
  137. local file=$(readlink -m "${file}")
  138. [ ! -e "$file" ]
  139. }
  140. assert_file() {
  141. local file="$1"
  142. local type=$2
  143. local user=$3
  144. local group=$4
  145. local privileges=$5
  146. assert_file_exist "$file"
  147. if [ "$type" = "d" ]; then
  148. if [ ! -d "$file" ]; then
  149. echo "[$file] should be a directory but is not"
  150. fi
  151. [ -d "$file" ]
  152. else
  153. if [ ! -f "$file" ]; then
  154. echo "[$file] should be a regular file but is not"
  155. fi
  156. [ -f "$file" ]
  157. fi
  158. if [ "x$user" != "x" ]; then
  159. realuser=$(find "$file" -maxdepth 0 -printf "%u")
  160. if [ "$realuser" != "$user" ]; then
  161. echo "Expected user: $user, found $realuser [$file]"
  162. fi
  163. [ "$realuser" = "$user" ]
  164. fi
  165. if [ "x$group" != "x" ]; then
  166. realgroup=$(find "$file" -maxdepth 0 -printf "%g")
  167. if [ "$realgroup" != "$group" ]; then
  168. echo "Expected group: $group, found $realgroup [$file]"
  169. fi
  170. [ "$realgroup" = "$group" ]
  171. fi
  172. if [ "x$privileges" != "x" ]; then
  173. realprivileges=$(find "$file" -maxdepth 0 -printf "%m")
  174. if [ "$realprivileges" != "$privileges" ]; then
  175. echo "Expected privileges: $privileges, found $realprivileges [$file]"
  176. fi
  177. [ "$realprivileges" = "$privileges" ]
  178. fi
  179. }
  180. assert_module_or_plugin_directory() {
  181. local directory=$1
  182. shift
  183. #owner group and permissions vary depending on how es was installed
  184. #just make sure that everything is the same as $CONFIG_DIR, which was properly set up during install
  185. config_user=$(find "$ESHOME" -maxdepth 0 -printf "%u")
  186. config_owner=$(find "$ESHOME" -maxdepth 0 -printf "%g")
  187. assert_file $directory d $config_user $config_owner 755
  188. }
  189. assert_module_or_plugin_file() {
  190. local file=$1
  191. shift
  192. assert_file_exist "$(readlink -m $file)"
  193. assert_file $file f $config_user $config_owner 644
  194. }
  195. assert_output() {
  196. echo "$output" | grep -E "$1"
  197. }
  198. # Deletes everything before running a test file
  199. clean_before_test() {
  200. # List of files to be deleted
  201. ELASTICSEARCH_TEST_FILES=("/usr/share/elasticsearch" \
  202. "/etc/elasticsearch" \
  203. "/var/lib/elasticsearch" \
  204. "/var/log/elasticsearch" \
  205. "/tmp/elasticsearch" \
  206. "/etc/default/elasticsearch" \
  207. "/etc/sysconfig/elasticsearch" \
  208. "/var/run/elasticsearch" \
  209. "/usr/share/doc/elasticsearch" \
  210. "/usr/share/doc/elasticsearch-oss" \
  211. "/tmp/elasticsearch" \
  212. "/usr/lib/systemd/system/elasticsearch.conf" \
  213. "/usr/lib/tmpfiles.d/elasticsearch.conf" \
  214. "/usr/lib/sysctl.d/elasticsearch.conf")
  215. # Kills all processes of user elasticsearch
  216. if id elasticsearch > /dev/null 2>&1; then
  217. pkill -u elasticsearch 2>/dev/null || true
  218. fi
  219. # Kills all running Elasticsearch processes
  220. ps aux | grep -i "org.elasticsearch.bootstrap.Elasticsearch" | awk {'print $2'} | xargs kill -9 > /dev/null 2>&1 || true
  221. purge_elasticsearch
  222. # Removes user & group
  223. userdel elasticsearch > /dev/null 2>&1 || true
  224. groupdel elasticsearch > /dev/null 2>&1 || true
  225. # Removes all files
  226. for d in "${ELASTICSEARCH_TEST_FILES[@]}"; do
  227. if [ -e "$d" ]; then
  228. rm -rf "$d"
  229. fi
  230. done
  231. if is_systemd; then
  232. systemctl unmask systemd-sysctl.service
  233. fi
  234. }
  235. purge_elasticsearch() {
  236. # Removes RPM package
  237. if is_rpm; then
  238. rpm --quiet -e $PACKAGE_NAME > /dev/null 2>&1 || true
  239. fi
  240. if [ -x "`which yum 2>/dev/null`" ]; then
  241. yum remove -y $PACKAGE_NAME > /dev/null 2>&1 || true
  242. fi
  243. # Removes DEB package
  244. if is_dpkg; then
  245. dpkg --purge $PACKAGE_NAME > /dev/null 2>&1 || true
  246. fi
  247. if [ -x "`which apt-get 2>/dev/null`" ]; then
  248. apt-get --quiet --yes purge $PACKAGE_NAME > /dev/null 2>&1 || true
  249. fi
  250. }
  251. # Start elasticsearch and wait for it to come up with a status.
  252. # $1 - expected status - defaults to green
  253. start_elasticsearch_service() {
  254. local desiredStatus=${1:-green}
  255. local index=$2
  256. local commandLineArgs=$3
  257. run_elasticsearch_service 0 $commandLineArgs
  258. wait_for_elasticsearch_status $desiredStatus $index
  259. if [ -r "/tmp/elasticsearch/elasticsearch.pid" ]; then
  260. pid=$(cat /tmp/elasticsearch/elasticsearch.pid)
  261. [ "x$pid" != "x" ] && [ "$pid" -gt 0 ]
  262. echo "Looking for elasticsearch pid...."
  263. ps $pid
  264. elif is_systemd; then
  265. run systemctl is-active elasticsearch.service
  266. [ "$status" -eq 0 ]
  267. run systemctl status elasticsearch.service
  268. [ "$status" -eq 0 ]
  269. elif is_sysvinit; then
  270. run service elasticsearch status
  271. [ "$status" -eq 0 ]
  272. fi
  273. }
  274. # Start elasticsearch
  275. # $1 expected status code
  276. # $2 additional command line args
  277. run_elasticsearch_service() {
  278. local expectedStatus=$1
  279. local commandLineArgs=$2
  280. # Set the ES_PATH_CONF setting in case we start as a service
  281. if [ ! -z "$ES_PATH_CONF" ] ; then
  282. if is_dpkg; then
  283. echo "ES_PATH_CONF=$ES_PATH_CONF" >> /etc/default/elasticsearch;
  284. elif is_rpm; then
  285. echo "ES_PATH_CONF=$ES_PATH_CONF" >> /etc/sysconfig/elasticsearch;
  286. fi
  287. fi
  288. if [ -f "/tmp/elasticsearch/bin/elasticsearch" ]; then
  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_PATH_CONF=$ES_PATH_CONF
  307. export ES_JAVA_OPTS=$ES_JAVA_OPTS
  308. $timeoutCommand/tmp/elasticsearch/bin/elasticsearch $background -p /tmp/elasticsearch/elasticsearch.pid $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. # the default netcat packages in the distributions we test are not all compatible
  344. # so we use /dev/tcp - a feature of bash which makes tcp connections
  345. # http://tldp.org/LDP/abs/html/devref1.html#DEVTCP
  346. test_port() {
  347. local host="$1"
  348. local port="$2"
  349. cat < /dev/null > "/dev/tcp/$host/$port"
  350. }
  351. describe_port() {
  352. local host="$1"
  353. local port="$2"
  354. if test_port "$host" "$port"; then
  355. echo "port $port on host $host is open"
  356. else
  357. echo "port $port on host $host is not open"
  358. fi
  359. }
  360. debug_collect_logs() {
  361. local es_logfile="$ESLOG/elasticsearch_server.json"
  362. local system_logfile='/var/log/messages'
  363. if [ -e "$es_logfile" ]; then
  364. echo "Here's the elasticsearch log:"
  365. cat "$es_logfile"
  366. else
  367. echo "The elasticsearch log doesn't exist at $es_logfile"
  368. fi
  369. if [ -e "$system_logfile" ]; then
  370. echo "Here's the tail of the log at $system_logfile:"
  371. tail -n20 "$system_logfile"
  372. else
  373. echo "The logfile at $system_logfile doesn't exist"
  374. fi
  375. echo "Current java processes:"
  376. ps aux | grep java || true
  377. echo "Testing if ES ports are open:"
  378. describe_port 127.0.0.1 9200
  379. describe_port 127.0.0.1 9201
  380. }
  381. set_debug_logging() {
  382. if [ "$ESCONFIG" ] && [ -d "$ESCONFIG" ] && [ -f /etc/os-release ] && (grep -qi suse /etc/os-release); then
  383. echo 'logger.org.elasticsearch.indices: TRACE' >> "$ESCONFIG/elasticsearch.yml"
  384. echo 'logger.org.elasticsearch.gateway: TRACE' >> "$ESCONFIG/elasticsearch.yml"
  385. echo 'logger.org.elasticsearch.cluster: DEBUG' >> "$ESCONFIG/elasticsearch.yml"
  386. fi
  387. }
  388. # Waits for Elasticsearch to reach some status.
  389. # $1 - expected status - defaults to green
  390. wait_for_elasticsearch_status() {
  391. local desiredStatus=${1:-green}
  392. local index=$2
  393. echo "Making sure elasticsearch is up..."
  394. wget -O - --retry-connrefused --waitretry=1 --timeout=120 --tries=120 http://localhost:9200/_cluster/health || {
  395. echo "Looks like elasticsearch never started"
  396. debug_collect_logs
  397. false
  398. }
  399. if [ -z "index" ]; then
  400. echo "Tring to connect to elasticsearch and wait for expected status $desiredStatus..."
  401. curl -sS "http://localhost:9200/_cluster/health?wait_for_status=$desiredStatus&timeout=60s&pretty"
  402. else
  403. echo "Trying to connect to elasticsearch and wait for expected status $desiredStatus for index $index"
  404. curl -sS "http://localhost:9200/_cluster/health/$index?wait_for_status=$desiredStatus&timeout=60s&pretty"
  405. fi
  406. if [ $? -eq 0 ]; then
  407. echo "Connected"
  408. else
  409. echo "Unable to connect to Elasticsearch"
  410. false
  411. fi
  412. echo "Checking that the cluster health matches the waited for status..."
  413. run curl -sS -XGET 'http://localhost:9200/_cat/health?h=status&v=false'
  414. if [ "$status" -ne 0 ]; then
  415. echo "error when checking cluster health. code=$status output="
  416. echo $output
  417. false
  418. fi
  419. echo $output | grep $desiredStatus || {
  420. echo "unexpected status: '$output' wanted '$desiredStatus'"
  421. false
  422. }
  423. }
  424. # Checks the current elasticsearch version using the Info REST endpoint
  425. # $1 - expected version
  426. check_elasticsearch_version() {
  427. local version=$1
  428. local versionToCheck
  429. local major=$(echo ${version} | cut -d. -f1 )
  430. if [ $major -ge 7 ] ; then
  431. versionToCheck=$version
  432. else
  433. versionToCheck=$(echo ${version} | sed -e 's/-SNAPSHOT//')
  434. fi
  435. run curl -s localhost:9200
  436. [ "$status" -eq 0 ]
  437. echo $output | grep \"number\"\ :\ \"$versionToCheck\" || {
  438. echo "Expected $versionToCheck but installed an unexpected version:"
  439. curl -s localhost:9200
  440. false
  441. }
  442. }
  443. # Executes some basic Elasticsearch tests
  444. run_elasticsearch_tests() {
  445. # TODO this assertion is the same the one made when waiting for
  446. # elasticsearch to start
  447. run curl -XGET 'http://localhost:9200/_cat/health?h=status&v=false'
  448. [ "$status" -eq 0 ]
  449. echo "$output" | grep -w "green"
  450. curl -s -H "Content-Type: application/json" -XPOST 'http://localhost:9200/library/_doc/1?refresh=true&pretty' -d '{
  451. "title": "Book #1",
  452. "pages": 123
  453. }'
  454. curl -s -H "Content-Type: application/json" -XPOST 'http://localhost:9200/library/_doc/2?refresh=true&pretty' -d '{
  455. "title": "Book #2",
  456. "pages": 456
  457. }'
  458. curl -s -XGET 'http://localhost:9200/_count?pretty' |
  459. grep \"count\"\ :\ 2
  460. curl -s -XDELETE 'http://localhost:9200/_all'
  461. }
  462. # Move the config directory to another directory and properly chown it.
  463. move_config() {
  464. local oldConfig="$ESCONFIG"
  465. # The custom config directory is not under /tmp or /var/tmp because
  466. # systemd's private temp directory functionally means different
  467. # processes can have different views of what's in these directories
  468. export ESCONFIG="${1:-$(mktemp -p /etc -d -t 'config.XXXX')}"
  469. echo "Moving configuration directory from $oldConfig to $ESCONFIG"
  470. # Move configuration files to the new configuration directory
  471. mv "$oldConfig"/* "$ESCONFIG"
  472. chown -R elasticsearch:elasticsearch "$ESCONFIG"
  473. assert_file_exist "$ESCONFIG/elasticsearch.yml"
  474. assert_file_exist "$ESCONFIG/jvm.options"
  475. assert_file_exist "$ESCONFIG/log4j2.properties"
  476. }
  477. # permissions from the user umask with the executable bit set
  478. executable_privileges_for_user_from_umask() {
  479. local user=$1
  480. shift
  481. echo $((0777 & ~$(sudo -E -u $user sh -c umask) | 0111))
  482. }
  483. # permissions from the user umask without the executable bit set
  484. file_privileges_for_user_from_umask() {
  485. local user=$1
  486. shift
  487. echo $((0777 & ~$(sudo -E -u $user sh -c umask) & ~0111))
  488. }
  489. # move java to simulate it not being in the path
  490. move_java() {
  491. which_java=`command -v java`
  492. assert_file_exist $which_java
  493. mv $which_java ${which_java}.bak
  494. }
  495. # move java back to its original location
  496. unmove_java() {
  497. which_java=`command -v java.bak`
  498. assert_file_exist $which_java
  499. mv $which_java `dirname $which_java`/java
  500. }