kea-admin.in 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614
  1. #!/bin/sh
  2. # Copyright (C) 2014-2015 Internet Systems Consortium, Inc. ("ISC")
  3. #
  4. # Permission to use, copy, modify, and/or distribute this software for any
  5. # purpose with or without fee is hereby granted, provided that the above
  6. # copyright notice and this permission notice appear in all copies.
  7. #
  8. # THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
  9. # REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
  10. # AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
  11. # INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  12. # LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
  13. # OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  14. # PERFORMANCE OF THIS SOFTWARE.
  15. # This is kea-admin script that conducts administrative tasks on the Kea
  16. # installation. Currently supported operations are:
  17. #
  18. # - lease database init
  19. # - lease database version check
  20. # - lease database version upgrade
  21. # Get the location of the kea-admin scripts
  22. prefix=@prefix@
  23. SCRIPTS_DIR_DEFAULT=@datarootdir@/@PACKAGE@/scripts
  24. scripts_dir=${SCRIPTS_DIR_DEFAULT}
  25. # These are the default parameters. They will likely not work in any
  26. # specific deployment.
  27. db_user="keatest"
  28. db_password="keatest"
  29. db_name="keatest"
  30. # lease dump parameters
  31. dump_type=0
  32. dump_file=""
  33. dump_qry=""
  34. # Include utilities. Use installed version if available and
  35. # use build version if it isn't.
  36. if [ -e @datarootdir@/@PACKAGE_NAME@/scripts/admin-utils.sh ]; then
  37. . @datarootdir@/@PACKAGE_NAME@/scripts/admin-utils.sh
  38. else
  39. . @abs_top_builddir@/src/bin/admin/admin-utils.sh
  40. fi
  41. # Prints out usage version.
  42. usage() {
  43. printf "kea-admin @PACKAGE_VERSION@\n"
  44. printf "\n"
  45. printf "This is a kea-admin script that conducts administrative tasks on\n"
  46. printf "the Kea installation.\n"
  47. printf "\n"
  48. printf "Usage: $0 COMMAND BACKEND [parameters]\n"
  49. printf "\n"
  50. printf "COMMAND: Currently supported operations are:\n"
  51. printf "\n"
  52. printf " - lease-init: Initalizes new lease database. Useful for first time installation.\n"
  53. printf " - lease-version: Checks version of the existing lease database scheme. Useful\n"
  54. printf " - for checking lease DB version when preparing for an upgrade.\n"
  55. printf " - lease-upgrade: Upgrades your lease database scheme\n"
  56. printf " - lease-dump: Dump current leases to a CSV file\n"
  57. printf "\n"
  58. printf "BACKEND - one of the supported backends: memfile|mysql|pgsql\n"
  59. printf "\n"
  60. printf "PARAMETERS: Parameters are optional in general, but may be required\n"
  61. printf " for specific operation.\n"
  62. printf " -u or --user name - specifies username when connecting to a database\n"
  63. printf " -p or --password pass - specifies a password when connecting to a database\n"
  64. printf " -n or --name database - specifies a database name to connect to\n"
  65. printf " -d or --directory - path to upgrade scripts (default: ${SCRIPTS_DIR_DEFAULT})\n"
  66. printf "\n"
  67. printf " Parameters specific to lease-dump:\n"
  68. printf " -4 to dump IPv4 leases to file\n"
  69. printf " -6 to dump IPv6 leases to file\n"
  70. printf " -o or --output - name of file to which leases will be dumped\n"
  71. }
  72. ### Logging functions ###
  73. # Logs message at the error level.
  74. # Takes one parameter that is printed as is.
  75. log_error() {
  76. printf "ERROR/kea-admin: ${1}\n"
  77. }
  78. # Logs message at the warning level.
  79. # Takes one parameter that is printed as is.
  80. log_warning() {
  81. printf "WARNING/kea-admin: ${1}\n"
  82. }
  83. # Logs message at the info level.
  84. # Takes one parameter that is printed as is.
  85. log_info() {
  86. printf "INFO/kea-admin: ${1}\n"
  87. }
  88. ### Convenience functions ###
  89. # Checks if the value is in the list. An example usage of this function
  90. # is to determine whether the kea-admin command belongs to the list of
  91. # supported commands.
  92. is_in_list() {
  93. local member=${1} # Value to be checked
  94. local list="${2}" # Comma separated list of items
  95. _inlist=0 # Return value: 0 if not in list, 1 otherwise.
  96. if [ -z ${member} ]; then
  97. log_error "missing ${class}"
  98. fi
  99. # Iterate over all items on the list and compare with the member.
  100. # If they match, return, otherwise log error and exit.
  101. for item in ${list}
  102. do
  103. if [ ${item} = ${member} ]; then
  104. _inlist=1
  105. return
  106. fi
  107. done
  108. }
  109. ### Functions that implement database initialization commands
  110. memfile_init() {
  111. # @todo Implement this as part of #3601
  112. log_error "NOT IMPLEMENTED"
  113. exit 1
  114. }
  115. # Initializes a new, empty MySQL database.
  116. # It essentially calls scripts/mysql/dhcpdb_create.mysql script, with
  117. # some extra sanity checks. It will refuse to use it if there are any
  118. # existing tables. It's better safe than sorry.
  119. mysql_init() {
  120. printf "Checking if there is a database initialized already. Please ignore errors.\n"
  121. # Let's try to count the number of tables. Anything above 0 means that there
  122. # is some database in place. If there is anything, we abort. Note that
  123. # mysql may spit out connection or access errors to stderr, we ignore those.
  124. # We should not hide them as they may give hints to user what is wrong with
  125. # his setup.
  126. #
  127. RESULT=`mysql_execute "SHOW TABLES;"`
  128. ERRCODE=$?
  129. if [ $ERRCODE -ne 0 ]
  130. then
  131. log_error "mysql_init table query failed, mysql status = $ERRCODE"
  132. exit 1
  133. fi
  134. COUNT=`echo $RESULT | wc -w`
  135. if [ $COUNT -gt 0 ]; then
  136. # Let't start with a new line. mysql could have printed something out.
  137. printf "\n"
  138. log_error "Expected empty database $db_name, but there are $COUNT tables: \n$_RESULT. Aborting."
  139. exit 1
  140. fi
  141. printf "Initializing database using script %s\n" $scripts_dir/mysql/dhcpdb_create.mysql
  142. mysql -B --user=$db_user --password=$db_password $db_name < $scripts_dir/mysql/dhcpdb_create.mysql
  143. ERRCODE=$?
  144. printf "mysql returned status code $ERRCODE\n"
  145. if [ "$ERRCODE" -eq 0 ]; then
  146. printf "Lease DB version reported after initialization: "
  147. mysql_version
  148. printf "\n"
  149. fi
  150. exit $ERRCODE
  151. }
  152. pgsql_init() {
  153. printf "Checking if there is a database initialized already. Please ignore errors.\n"
  154. # Let's try to count the number of tables. Anything above 0 means that there
  155. # is some database in place. If there is anything, we abort.
  156. RESULT=`pgsql_execute "\d"`
  157. ERRCODE=$?
  158. if [ "$ERRCODE" -ne 0 ]; then
  159. log_error "pgsql_init: table query failed, status code: $ERRCODE?"
  160. exit 1
  161. fi
  162. COUNT=`echo "$RESULT" | wc -w`
  163. if [ $COUNT -gt 0 ]; then
  164. printf "\n"
  165. log_error "Expected empty database $db_name, but the following tables are present \n$RESULT. Aborting."
  166. exit 2
  167. fi
  168. init_script="$scripts_dir/pgsql/dhcpdb_create.pgsql"
  169. printf "Initializing database using script %s\n" $init_script
  170. RESULT=`pgsql_execute_script $init_script`
  171. ERRCODE=$?
  172. if [ "$ERRCODE" -ne 0 ]; then
  173. log_error "Database initialization failed, status code: $ERRCODE?"
  174. exit 1
  175. fi
  176. version=`pgsql_version`
  177. printf "Lease DB version reported after initialization: $version\n"
  178. exit 0
  179. }
  180. ### Functions that implement database version checking commands
  181. memfile_version() {
  182. # @todo Implement this as part of #3601
  183. log_error "NOT IMPLEMENTED"
  184. exit 1
  185. }
  186. ### Functions used for upgrade
  187. memfile_upgrade() {
  188. # @todo Implement this as part of #3601
  189. log_error "NOT IMPLEMENTED"
  190. exit 1
  191. }
  192. # Upgrades existing MySQL database installation. The idea is that
  193. # it will go over all upgrade scripts from (prefix)/share/kea/scripts/mysql
  194. # and run them one by one. They will be named properly, so they will
  195. # be run in order.
  196. #
  197. # This function prints version before and after upgrade.
  198. mysql_upgrade() {
  199. printf "Lease DB version reported before upgrade: "
  200. mysql_version
  201. printf "\n"
  202. # Check if the scripts directory exists at all.
  203. if [ ! -d ${scripts_dir}/mysql ]; then
  204. log_error "Invalid scripts directory: ${scripts_dir}/mysql"
  205. exit 1
  206. fi
  207. # Check if there are any files in it
  208. num_files=$(find ${scripts_dir}/mysql/upgrade*.sh -type f | wc -l)
  209. if [ $num_files -eq 0 ]; then
  210. log_error "No scripts in ${scripts_dir}/mysql or the directory is not readable or does not have any upgrade* scripts."
  211. exit 1
  212. fi
  213. for script in ${scripts_dir}/mysql/upgrade*.sh
  214. do
  215. echo "Processing $script file..."
  216. sh ${script} --user=${db_user} --password=${db_password} ${db_name}
  217. done
  218. printf "Lease DB version reported after upgrade: "
  219. mysql_version
  220. printf "\n"
  221. }
  222. pgsql_upgrade() {
  223. version=`pgsql_version`
  224. printf "Lease DB version reported before upgrade: $version\n"
  225. # Check if the scripts directory exists at all.
  226. if [ ! -d ${scripts_dir}/pgsql ]; then
  227. log_error "Invalid scripts directory: ${scripts_dir}/pgsql"
  228. exit 1
  229. fi
  230. # Check if there are any files in it
  231. num_files=$(find ${scripts_dir}/pgsql/upgrade*.sh -type f | wc -l)
  232. if [ $num_files -eq 0 ]; then
  233. log_error "No scripts in ${scripts_dir}/pgsql or the directory is not readable or does not have any upgrade* scripts."
  234. exit 1
  235. fi
  236. for script in ${scripts_dir}/pgsql/upgrade*.sh
  237. do
  238. echo "Processing $script file..."
  239. sh ${script} --user=${db_user} --password=${db_password} ${db_name}
  240. done
  241. version=`pgsql_version`
  242. printf "Lease DB version reported after upgrade: $version\n"
  243. exit 0
  244. }
  245. # Utility function which tests if the given file exists and
  246. # if so notifies the user and provides them the opportunity
  247. # to abort the current command.
  248. check_file_overwrite () {
  249. local file=$1
  250. if [ -e ${file} ]
  251. then
  252. echo "Output file, $file, exists and will be overwritten."
  253. echo "Do you wish to continue? (y/n)"
  254. read ans
  255. if [ ${ans} != "y" ]
  256. then
  257. echo "$command aborted by user."
  258. exit 1
  259. fi
  260. fi
  261. }
  262. ### Functions used for dump
  263. # Sets the global variable, dump_qry, to the schema-version specific
  264. # SQL text needed to dump the lease data for the current backend
  265. # and protocol
  266. get_dump_query() {
  267. local version=$1
  268. dump_qry=""
  269. dump_sql_file="$scripts_dir/${backend}/lease_dump_$version.sh"
  270. if [ ! -e $dump_sql_file ]
  271. then
  272. log_error "lease-dump: cannot access dump_sql_file: $dump_sql_file"
  273. exit 1;
  274. fi
  275. # source in the dump file which defines the sql text we'll need
  276. . $dump_sql_file
  277. if [ $? -ne 0 ]
  278. then
  279. log_error "lease-dump: error sourcing dump_sql_file: $dump_sql_file"
  280. exit 1
  281. fi
  282. # Construct the SQL text to dump the leases based on protocol type
  283. case ${dump_type} in
  284. 4)
  285. dump_qry="$lease4_dump_sql";
  286. ;;
  287. 6)
  288. dump_qry="$lease6_dump_sql";
  289. ;;
  290. *)
  291. log_error "you must specify -4 or -6 for lease-dump"
  292. usage
  293. exit 1
  294. ;;
  295. esac
  296. if [ "$dump_qry" = "" ]
  297. then
  298. log_error "lease-dump: dump query appears to be undefined"
  299. exit 1
  300. fi
  301. }
  302. memfile_dump() {
  303. log_error "lease-dump is not supported for memfile"
  304. exit 1
  305. }
  306. mysql_dump() {
  307. # get the correct dump query
  308. version=`mysql_version`
  309. retcode=$?
  310. if [ $retcode -ne 0 ]
  311. then
  312. log_error "lease-dump: mysql_version failed, exit code $retcode"
  313. exit 1;
  314. fi
  315. # Fetch the correct SQL text. Note this function will exit
  316. # if it fails.
  317. get_dump_query $version
  318. # Make sure they specified a file
  319. if [ "$dump_file" = "" ]; then
  320. log_error "you must specify an output file for lease-dump"
  321. usage
  322. exit 1
  323. fi
  324. # If output file exists, notify user, allow them a chance to bail
  325. check_file_overwrite $dump_file
  326. # Check the temp file too
  327. tmp_file="$dump_file.tmp"
  328. check_file_overwrite $tmp_file
  329. # Run the sql to output tab-delimited lease data to a temp file.
  330. # By using a temp file we can check for MySQL errors before using
  331. # 'tr' to translate tabs to commas. We do not use MySQL's output
  332. # to file as that requires linux superuser privileges to execute
  333. # the select.
  334. mysql_execute "${dump_qry}" > $tmp_file
  335. retcode=$?
  336. if [ $retcode -ne 0 ]; then
  337. log_error "lease-dump: mysql_execute failed, exit code $retcode";
  338. exit 1
  339. fi
  340. # Now translate tabs to commas.
  341. cat $tmp_file | tr '\t' ',' >$dump_file
  342. if [ $? -ne 0 ]; then
  343. log_error "lease-dump: reformatting failed";
  344. exit 1
  345. fi
  346. # delete the tmp file on success
  347. rm $tmp_file
  348. echo lease$dump_type successfully dumped to $dump_file
  349. exit 0
  350. }
  351. ### Functions used for dump
  352. pgsql_dump() {
  353. version=`pgsql_version`
  354. get_dump_query $version
  355. # Make sure they specified a file
  356. if [ "$dump_file" = "" ]; then
  357. log_error "you must specify an output file for lease-dump"
  358. usage
  359. exit 1
  360. fi
  361. # If output file exists, notify user, allow them a chance to bail
  362. check_file_overwrite $dump_file
  363. # psql does not accept password as a parameter but will look in the environment
  364. export PGPASSWORD=$db_password
  365. # Call psql and redirect output to the dump file. We don't use psql "to csv"
  366. # as it can only be run as db superuser.
  367. echo "$dump_qry" | psql --set ON_ERROR_STOP=1 -t -q --user=$db_user --dbname=$db_name -w --no-align --field-separator=',' >$dump_file
  368. retcode=$?
  369. # Check for errors.
  370. if [ $retcode -ne 0 ]; then
  371. log_error "lease-dump: psql call failed, exit code: $retcode";
  372. exit 1
  373. fi
  374. echo lease$dump_type successfully dumped to $dump_file
  375. exit 0
  376. }
  377. ### Script starts here ###
  378. # First, find what the command is
  379. command=${1}
  380. if [ -z ${command} ]; then
  381. log_error "missing command"
  382. usage
  383. exit 1
  384. fi
  385. is_in_list "${command}" "lease-init lease-version lease-upgrade lease-dump"
  386. if [ ${_inlist} -eq 0 ]; then
  387. log_error "invalid command: ${command}"
  388. exit 1
  389. fi
  390. shift
  391. # Second, check what's the backend
  392. backend=${1}
  393. if [ -z ${backend} ]; then
  394. log_error "missing backend"
  395. usage
  396. exit 1
  397. fi
  398. is_in_list "${backend}" "memfile mysql pgsql"
  399. if [ ${_inlist} -eq 0 ]; then
  400. log_error "invalid backend: ${backend}"
  401. exit 1
  402. fi
  403. shift
  404. # Ok, let's process parameters (if there are any)
  405. while [ ! -z "${1}" ]
  406. do
  407. option=${1}
  408. case ${option} in
  409. # Specify database user
  410. -u|--user)
  411. shift
  412. db_user=${1}
  413. if [ -z ${db_user} ]; then
  414. log_error "-u or --user requires a parameter"
  415. usage
  416. exit 1
  417. fi
  418. ;;
  419. # Specify database password
  420. -p|--password)
  421. shift
  422. db_password=${1}
  423. if [ -z ${db_password} ]; then
  424. log_error "-p or --password requires a parameter"
  425. usage
  426. exit 1
  427. fi
  428. ;;
  429. # Specify database name
  430. -n|--name)
  431. shift
  432. db_name=${1}
  433. if [ -z ${db_name} ]; then
  434. log_error "-n or --name requires a parameter"
  435. usage
  436. exit 1
  437. fi
  438. ;;
  439. -d|--directory)
  440. shift
  441. scripts_dir=${1}
  442. if [ -z ${scripts_dir} ]; then
  443. log_error "-d or --directory requires a parameter"
  444. usage
  445. exit 1
  446. fi
  447. ;;
  448. # specify DHCPv4 lease type
  449. -4)
  450. if [ $dump_type -eq 6 ]; then
  451. log_error "you may not specify both -4 and -6"
  452. usage
  453. exit 1
  454. fi
  455. dump_type=4
  456. ;;
  457. # specify DHCPv6 lease type
  458. -6)
  459. if [ $dump_type -eq 4 ]; then
  460. log_error "you may not specify both -4 and -6"
  461. usage
  462. exit 1
  463. fi
  464. dump_type=6
  465. ;;
  466. # specify output file, currently only used by lease dump
  467. -o|--output)
  468. shift
  469. dump_file=${1}
  470. if [ -z ${dump_file} ]; then
  471. log_error "-o or --output requires a parameter"
  472. usage
  473. exit 1
  474. fi
  475. ;;
  476. *)
  477. log_error "invalid option: ${option}"
  478. usage
  479. exit 1
  480. esac
  481. shift
  482. done
  483. case ${command} in
  484. # Initialize the database
  485. lease-init)
  486. case ${backend} in
  487. memfile)
  488. memfile_init
  489. ;;
  490. mysql)
  491. mysql_init
  492. ;;
  493. pgsql)
  494. pgsql_init
  495. ;;
  496. esac
  497. ;;
  498. lease-version)
  499. case ${backend} in
  500. memfile)
  501. memfile_version
  502. ;;
  503. mysql)
  504. mysql_version
  505. printf "\n"
  506. ;;
  507. pgsql)
  508. pgsql_version
  509. ;;
  510. esac
  511. ;;
  512. lease-upgrade)
  513. case ${backend} in
  514. memfile)
  515. memfile_upgrade
  516. ;;
  517. mysql)
  518. mysql_upgrade
  519. ;;
  520. pgsql)
  521. pgsql_upgrade
  522. ;;
  523. esac
  524. ;;
  525. lease-dump)
  526. case ${backend} in
  527. memfile)
  528. memfile_dump
  529. ;;
  530. mysql)
  531. mysql_dump
  532. ;;
  533. pgsql)
  534. pgsql_dump
  535. ;;
  536. esac
  537. ;;
  538. esac
  539. exit 0