github.com/observiq/carbon@v0.9.11-0.20200820160507-1b872e368a5e/scripts/unix-install.sh (about) 1 #!/bin/sh 2 # shellcheck disable=SC2119 3 # SC2119 -> Use foo "$@" if function's $1 should mean script's $1. 4 5 set -e 6 7 # Agent Constants 8 SERVICE_NAME="carbon" 9 BINARY_NAME="carbon" 10 DOWNLOAD_BASE="https://github.com/observiq/carbon/releases" 11 PLUGINS_PACKAGE="carbon-plugins.tar.gz" 12 13 # Script Constants 14 PREREQS="curl hostname printf ps sed uname cut tar" 15 SCRIPT_NAME="$0" 16 INDENT_WIDTH=' ' 17 indent="" 18 REQUIRE_SECRET_KEY="false" 19 20 # Colors 21 num_colors=$(tput colors 2>/dev/null) 22 if test -n "$num_colors" && test "$num_colors" -ge 8; then 23 bold="$(tput bold)" 24 underline="$(tput smul)" 25 # standout can be bold or reversed colors dependent on terminal 26 standout="$(tput smso)" 27 reset="$(tput sgr0)" 28 bg_black="$(tput setab 0)" 29 bg_blue="$(tput setab 4)" 30 bg_cyan="$(tput setab 6)" 31 bg_green="$(tput setab 2)" 32 bg_magenta="$(tput setab 5)" 33 bg_red="$(tput setab 1)" 34 bg_white="$(tput setab 7)" 35 bg_yellow="$(tput setab 3)" 36 fg_black="$(tput setaf 0)" 37 fg_blue="$(tput setaf 4)" 38 fg_cyan="$(tput setaf 6)" 39 fg_green="$(tput setaf 2)" 40 fg_magenta="$(tput setaf 5)" 41 fg_red="$(tput setaf 1)" 42 fg_white="$(tput setaf 7)" 43 fg_yellow="$(tput setaf 3)" 44 fi 45 46 if [ -z "$reset" ]; then 47 sed_ignore='' 48 else 49 sed_ignore="/^[$reset]+$/!" 50 fi 51 52 # Helper Functions 53 printf() { 54 if command -v sed >/dev/null; then 55 command printf -- "$@" | sed -E "$sed_ignore s/^/$indent/g" # Ignore sole reset characters if defined 56 else 57 # Ignore $* suggestion as this breaks the output 58 # shellcheck disable=SC2145 59 command printf -- "$indent$@" 60 fi 61 } 62 63 increase_indent() { indent="$INDENT_WIDTH$indent" ; } 64 decrease_indent() { indent="${indent#*$INDENT_WIDTH}" ; } 65 66 # Color functions reset only when given an argument 67 bold() { command printf "$bold$*$(if [ -n "$1" ]; then command printf "$reset"; fi)" ; } 68 underline() { command printf "$underline$*$(if [ -n "$1" ]; then command printf "$reset"; fi)" ; } 69 standout() { command printf "$standout$*$(if [ -n "$1" ]; then command printf "$reset"; fi)" ; } 70 # Ignore "parameters are never passed" 71 # shellcheck disable=SC2120 72 reset() { command printf "$reset$*$(if [ -n "$1" ]; then command printf "$reset"; fi)" ; } 73 bg_black() { command printf "$bg_black$*$(if [ -n "$1" ]; then command printf "$reset"; fi)" ; } 74 bg_blue() { command printf "$bg_blue$*$(if [ -n "$1" ]; then command printf "$reset"; fi)" ; } 75 bg_cyan() { command printf "$bg_cyan$*$(if [ -n "$1" ]; then command printf "$reset"; fi)" ; } 76 bg_green() { command printf "$bg_green$*$(if [ -n "$1" ]; then command printf "$reset"; fi)" ; } 77 bg_magenta() { command printf "$bg_magenta$*$(if [ -n "$1" ]; then command printf "$reset"; fi)" ; } 78 bg_red() { command printf "$bg_red$*$(if [ -n "$1" ]; then command printf "$reset"; fi)" ; } 79 bg_white() { command printf "$bg_white$*$(if [ -n "$1" ]; then command printf "$reset"; fi)" ; } 80 bg_yellow() { command printf "$bg_yellow$*$(if [ -n "$1" ]; then command printf "$reset"; fi)" ; } 81 fg_black() { command printf "$fg_black$*$(if [ -n "$1" ]; then command printf "$reset"; fi)" ; } 82 fg_blue() { command printf "$fg_blue$*$(if [ -n "$1" ]; then command printf "$reset"; fi)" ; } 83 fg_cyan() { command printf "$fg_cyan$*$(if [ -n "$1" ]; then command printf "$reset"; fi)" ; } 84 fg_green() { command printf "$fg_green$*$(if [ -n "$1" ]; then command printf "$reset"; fi)" ; } 85 fg_magenta() { command printf "$fg_magenta$*$(if [ -n "$1" ]; then command printf "$reset"; fi)" ; } 86 fg_red() { command printf "$fg_red$*$(if [ -n "$1" ]; then command printf "$reset"; fi)" ; } 87 fg_white() { command printf "$fg_white$*$(if [ -n "$1" ]; then command printf "$reset"; fi)" ; } 88 fg_yellow() { command printf "$fg_yellow$*$(if [ -n "$1" ]; then command printf "$reset"; fi)" ; } 89 90 # Intentionally using variables in format string 91 # shellcheck disable=SC2059 92 info() { printf "$*\\n" ; } 93 # Intentionally using variables in format string 94 # shellcheck disable=SC2059 95 warn() { 96 increase_indent 97 printf "$fg_yellow$*$reset\\n" 98 decrease_indent 99 } 100 # Intentionally using variables in format string 101 # shellcheck disable=SC2059 102 error() { 103 increase_indent 104 printf "$fg_red$*$reset\\n" 105 decrease_indent 106 } 107 # Intentionally using variables in format string 108 # shellcheck disable=SC2059 109 success() { printf "$fg_green$*$reset\\n" ; } 110 # Ignore 'arguments are never passed' 111 # shellcheck disable=SC2120 112 prompt() { 113 if [ "$1" = 'n' ]; then 114 command printf "y/$(fg_red '[n]'): " 115 else 116 command printf "$(fg_green '[y]')/n: " 117 fi 118 } 119 120 separator() { printf "===================================================\\n" ; } 121 122 banner() 123 { 124 printf "\\n" 125 separator 126 printf "| %s\\n" "$*" ; 127 separator 128 } 129 130 usage() 131 { 132 increase_indent 133 USAGE=$(cat <<EOF 134 Usage: 135 $(fg_yellow '-v, --version') 136 Defines the version of the agent. 137 If not provided, this will default to the latest version. 138 139 $(fg_yellow '-i, --install-dir') 140 Defines the install directory of the agent. 141 If not provided, this will default to an OS specific location. 142 143 $(fg_yellow '-u, --service-user') 144 Defines the service user that will run the agent as a service. 145 If not provided, this will default to root. 146 147 EOF 148 ) 149 info "$USAGE" 150 decrease_indent 151 return 0 152 } 153 154 force_exit() 155 { 156 # Exit regardless of subshell level with no "Terminated" message 157 kill -PIPE $$ 158 # Call exit to handle special circumstances (like running script during docker container build) 159 exit 1 160 } 161 162 error_exit() 163 { 164 line_num=$(if [ -n "$1" ]; then command printf ":$1"; fi) 165 error "ERROR ($SCRIPT_NAME$line_num): ${2:-Unknown Error}" >&2 166 shift 2 167 if [ -n "$0" ]; then 168 increase_indent 169 error "$*" 170 decrease_indent 171 fi 172 force_exit 173 } 174 175 print_prereq_line() 176 { 177 if [ -n "$2" ]; then 178 command printf "\\n${indent} - " 179 command printf "[$1]: $2" 180 fi 181 } 182 183 check_failure() 184 { 185 if [ "$indent" != '' ]; then increase_indent; fi 186 command printf "${indent}${fg_red}ERROR: %s check failed!${reset}" "$1" 187 188 print_prereq_line "Issue" "$2" 189 print_prereq_line "Resolution" "$3" 190 print_prereq_line "Help Link" "$4" 191 print_prereq_line "Rerun" "$5" 192 193 command printf "\\n" 194 if [ "$indent" != '' ]; then decrease_indent; fi 195 force_exit 196 } 197 198 succeeded() 199 { 200 increase_indent 201 success "Succeeded!" 202 decrease_indent 203 } 204 205 failed() 206 { 207 error "Failed!" 208 } 209 210 # This will set all installation variables 211 # at the beginning of the script. 212 setup_installation() 213 { 214 banner "Configuring Installation Variables" 215 increase_indent 216 217 # Installation variables 218 set_os 219 set_download_urls 220 set_install_dir 221 set_agent_home 222 223 # Service variables 224 set_service_user 225 set_agent_binary 226 set_agent_log 227 set_agent_database 228 229 success "Configuration complete!" 230 decrease_indent 231 } 232 233 # This will set the os based on the current runtime environment. 234 # Accepted values are darwin and linux. This value cannot be overriden. 235 set_os() 236 { 237 os_key=$(uname -s) 238 case "$os_key" in 239 Darwin) 240 os="darwin" 241 ;; 242 Linux) 243 os="linux" 244 ;; 245 *) 246 error "Unsupported os type: $os_key" 247 ;; 248 esac 249 } 250 251 # This will set the urls to use when downloading the agent and its plugins. 252 # These urls are constructed based on the --version flag or CARBON_VERSION env variable. 253 # If not specified, the version defaults to "latest". 254 set_download_urls() 255 { 256 if [ -z "$version" ] ; then 257 # shellcheck disable=SC2153 258 version=$CARBON_VERSION 259 fi 260 261 if [ -z "$version" ] ; then 262 agent_download_url="$DOWNLOAD_BASE/latest/download/${BINARY_NAME}_${os}_amd64" 263 plugins_download_url="$DOWNLOAD_BASE/latest/download/${PLUGINS_PACKAGE}" 264 else 265 agent_download_url="$DOWNLOAD_BASE/download/$version/${BINARY_NAME}_${os}_amd64" 266 plugins_download_url="$DOWNLOAD_BASE/download/$version/${PLUGINS_PACKAGE}" 267 fi 268 } 269 270 # This will set the install directory of the agent. 271 # It is set by the --install-dir flag or CARBON_INSTALL_DIR env variable. 272 # If not specified, it defaults to an OS specific value. 273 set_install_dir() 274 { 275 if [ -z "$install_dir" ]; then 276 # shellcheck disable=SC2153 277 install_dir=$CARBON_INSTALL_DIR 278 fi 279 280 if [ -z "$install_dir" ]; then 281 case "$os" in 282 darwin) 283 install_dir=${HOME} 284 ;; 285 linux) 286 install_dir=/opt 287 ;; 288 esac 289 fi 290 } 291 292 # This will set agent_home, which is required to run the agent. 293 # The install directory must be set prior to this. 294 set_agent_home() 295 { 296 agent_home="$install_dir/observiq/carbon" 297 } 298 299 # This will set the user assigned to the agent service. 300 # It is set by the --service-user flag or CARBON_SERVICE_USER env variable. 301 # If not specified, it defaults to root. 302 set_service_user() 303 { 304 if [ -z "$service_user" ]; then 305 # shellcheck disable=SC2153 306 service_user=$CARBON_SERVICE_USER 307 fi 308 309 if [ -z "$service_user" ] ; then 310 service_user="root" 311 fi 312 } 313 314 # This will set the location of the binary used to launch the agent. 315 # This value cannot be overriden and is based on the location of agent_home. 316 set_agent_binary() 317 { 318 agent_binary="$agent_home/$BINARY_NAME" 319 } 320 321 # This will set the agent log location. 322 set_agent_log() 323 { 324 agent_log="$agent_home/$SERVICE_NAME.log" 325 } 326 327 # This will set the agent database file. 328 set_agent_database() 329 { 330 agent_database="$agent_home/$SERVICE_NAME.db" 331 } 332 333 # This will check all prerequisites before running an installation. 334 check_prereqs() 335 { 336 banner "Checking Prerequisites" 337 increase_indent 338 os_check 339 os_arch_check 340 dependencies_check 341 success "Prerequisite check complete!" 342 decrease_indent 343 } 344 345 # This will check if the operating system is supported. 346 os_check() 347 { 348 info "Checking that the operating system is supported..." 349 os_type=$(uname -s) 350 case "$os_type" in 351 Darwin|Linux) 352 succeeded 353 ;; 354 *) 355 failed 356 error_exit "The operating system $(fg_yellow "$os_type") is not supported by this script." 357 ;; 358 esac 359 } 360 361 # This will check if the system architecture is supported. 362 os_arch_check() 363 { 364 info "Checking for valid operating system architecture..." 365 os_arch=$(uname -m) 366 if [ "$os_arch" = 'x86_64' ]; then 367 succeeded 368 else 369 failed 370 error_exit "The operating system architecture $(fg_yellow "$os_arch") is not supported by this script." 371 fi 372 } 373 374 # This will check if the current environment has 375 # all required shell dependencies to run the installation. 376 dependencies_check() 377 { 378 info "Checking for script dependencies..." 379 FAILED_PREREQS='' 380 for prerequisite in $PREREQS; do 381 if command -v "$prerequisite" >/dev/null; then 382 continue 383 else 384 if [ -z "$FAILED_PREREQS" ]; then 385 FAILED_PREREQS="${fg_red}$prerequisite${reset}" 386 else 387 FAILED_PREREQS="$FAILED_PREREQS, ${fg_red}$prerequisite${reset}" 388 fi 389 fi 390 done 391 392 if [ -n "$FAILED_PREREQS" ]; then 393 failed 394 error_exit "The following dependencies are required by this script: [$FAILED_PREREQS]" 395 fi 396 succeeded 397 return 0 398 } 399 400 # This will install the package by downloading the archived agent, 401 # extracting the binaries, and then removing the archive. 402 install_package() 403 { 404 banner "Installing Carbon" 405 increase_indent 406 407 info "Creating Carbon directory..." 408 mkdir -p "$agent_home" 409 succeeded 410 411 info "Checking that service is not running..." 412 stop_service 413 succeeded 414 415 info "Downloading binary..." 416 curl -L "$agent_download_url" -o "$agent_binary" --progress-bar --fail || error_exit "$LINENO" "Failed to download package" 417 succeeded 418 419 info "Setting permissions..." 420 chmod +x "$agent_binary" 421 ln -sf "$agent_binary" "/usr/local/bin/$BINARY_NAME" 422 succeeded 423 424 info "Downloading plugins..." 425 mkdir -p "$agent_home/tmp" 426 curl -L "$plugins_download_url" -o "$agent_home/tmp/plugins.tar.gz" --progress-bar --fail || error_exit "$LINENO" "Failed to download plugins" 427 succeeded 428 429 info "Extracting plugins..." 430 tar -zxf "$agent_home/tmp/plugins.tar.gz" -C "$agent_home" 431 rm -fr "$agent_home/tmp" 432 433 success "Carbon installation complete!" 434 decrease_indent 435 } 436 437 # This will create the agent config as a YAML file. 438 generate_config() 439 { 440 banner "Generating Config" 441 increase_indent 442 443 info "Creating config file..." 444 config_file="$agent_home/config.yaml" 445 create_config_file "$config_file" 446 succeeded 447 448 success "Generation complete!" 449 decrease_indent 450 } 451 452 # This will the create a config file with an example pipeline. 453 create_config_file() 454 { 455 # Don't overwrite a config file that already exists 456 if [ -f "$1" ] ; then 457 return 458 fi 459 460 cat << EOF > "$1" 461 pipeline: 462 # An example input that generates a single log entry when Carbon starts up. 463 - type: generate_input 464 count: 1 465 entry: 466 record: This is a sample log generated by Carbon 467 output: example_output 468 469 # An example input that monitors the contents of a file. 470 # For more info: https://github.com/observIQ/carbon/blob/master/docs/operators/file_input.md 471 # 472 # - type: file_input 473 # include: 474 # - /sample/file/path 475 # output: example_output 476 477 # An example output that sends captured logs to stdout. 478 - id: example_output 479 type: stdout 480 481 # An example output that sends captured logs to google cloud logging. 482 # For more info: https://github.com/observIQ/carbon/blob/master/docs/operators/google_cloud_output.md 483 # 484 # - id: example_output 485 # type: google_cloud_output 486 # credentials_file: /my/credentials/file 487 488 # An example output that sends captured logs to elasticsearch. 489 # For more info: https://github.com/observIQ/carbon/blob/master/docs/operators/elastic_output.md 490 # 491 # - id: example_output 492 # type: elastic_output 493 # addresses: 494 # - http://my_node_address:9200 495 # api_key: my_api_key 496 EOF 497 } 498 499 # This will install the service by detecting the init system 500 # and configuring the launcher to run accordinngly 501 install_service() 502 { 503 banner "Creating Service" 504 increase_indent 505 506 service_type="$(init_type)" 507 case "$service_type" in 508 launchd) 509 create_launchd_service 510 ;; 511 sysv|upstart) 512 create_sysv_service 513 ;; 514 systemd) 515 create_systemd_service 516 ;; 517 *) 518 error "Your init system ($fg_yellow$service_type$fg_red) is not supported." 519 error "The agent must be started manually by running $agent_binary" 520 service_install_failed="true" 521 esac 522 523 if [ "$service_install_failed" = "true" ] ; then 524 error "Failed to install service" 525 else 526 success "Service installation complete" 527 fi 528 decrease_indent 529 } 530 531 # This is used to discover the init system for a unix environment. It supports 532 # launchd, upstart, systemd, and sysv. 533 init_type() 534 { 535 if [ "$os" = darwin ]; then 536 command printf "launchd" 537 return 538 fi 539 540 ubuntu_test="$(ubuntu_init_type)" 541 if [ "$ubuntu_test" != "unknown" ]; then 542 command printf "$ubuntu_test" 543 return 544 fi 545 546 upstart_test="$( (/sbin/init --version || :) 2>&1)" 547 if command printf "$upstart_test" | grep -q 'upstart'; then 548 command printf "upstart" 549 return 550 fi 551 552 systemd_test="$(systemctl || : 2>&1)" 553 if command printf "$systemd_test" | grep -q '\-.mount'; then 554 command printf "systemd" 555 return 556 fi 557 558 if [ -f /etc/init.d/cron ] && [ ! -L /etc/init.d/cron ]; then 559 command printf "sysv" 560 return 561 fi 562 563 command printf "unknown" 564 return 565 } 566 567 # This exists because Ubuntu (at least 16.04 LTS) has both upstart and systemd installed. If this machine 568 # is running Ubuntu, check which of those systems is being used. If it's not running Ubuntu, then just 569 # return "unknown", which will tell the calling function to continue with the other tests 570 ubuntu_init_type() 571 { 572 if uname -a | grep -q Ubuntu; then 573 # shellcheck disable=SC2009 574 if ps -p1 | grep -q systemd; then 575 command printf 'systemd' 576 else 577 command printf 'upstart' 578 fi 579 else 580 command printf "unknown" 581 fi 582 } 583 584 # This will detect the service type and stop it 585 stop_service() 586 { 587 service_type="$(init_type)" 588 case "$service_type" in 589 launchd) 590 stop_launchd_service 591 ;; 592 sysv|upstart) 593 stop_sysv_service 594 ;; 595 systemd) 596 stop_systemd_service 597 ;; 598 esac 599 } 600 601 # This will configure the agent to run as a service with launchd. 602 create_launchd_service() 603 { 604 PLISTFILE="${HOME}/Library/LaunchAgents/com.observiq.${SERVICE_NAME}.plist" 605 replace_service="false" 606 607 if [ -e "$PLISTFILE" ]; then 608 request_service_replacement 609 if [ $replace_service = "true" ]; then 610 launchctl stop "com.observiq.${SERVICE_NAME}" || warn "Failed to stop service" 611 launchctl unload "${PLISTFILE}" 2>/dev/null 612 else 613 return 0 614 fi 615 fi 616 617 mkdir -p "${HOME}/Library/LaunchAgents" 618 info "Creating service file..." 619 create_launchd_file "$PLISTFILE" 620 succeeded 621 622 info "Loading service file..." 623 launchctl load "$PLISTFILE" 2>/dev/null 624 succeeded 625 626 info "Starting service..." 627 start_launchd_service 628 succeeded 629 630 startup_cmd="launchctl start com.observiq.$SERVICE_NAME" 631 shutdown_cmd="launchctl stop com.observiq.$SERVICE_NAME" 632 } 633 634 # This will create the launchd plist file. 635 create_launchd_file() 636 { 637 cat > "$1" << PLISTFILECON 638 <?xml version="1.0" encoding="UTF-8"?> 639 <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> 640 <plist version="1.0"> 641 <dict> 642 <key>Label</key> 643 <string>com.observiq.${SERVICE_NAME}</string> 644 <key>Program</key> 645 <string>$agent_binary</string> 646 <key>ProgramArguments</key> 647 <array> 648 <string>$agent_binary</string> 649 <string>--log_file</string> 650 <string>$agent_log</string> 651 <string>--database</string> 652 <string>$agent_database</string> 653 </array> 654 <key>WorkingDirectory</key> 655 <string>$agent_home</string> 656 <key>RunAtLoad</key> 657 <true/> 658 <key>SessionCreate</key> 659 <true/> 660 <key>UserName</key> 661 <string>$service_user</string> 662 </dict> 663 </plist> 664 PLISTFILECON 665 } 666 667 # This will start the launchd service. It will fail 668 # if unsuccessful. 669 start_launchd_service() 670 { 671 launchctl start "com.observiq.${SERVICE_NAME}" 672 673 RET="$?" 674 if [ "$RET" -eq 3 ]; then 675 error_exit $LINENO "launchctl is unable to start the $SERVICE_NAME service unless the user is logged in via a GUI." 676 elif [ "$RET" -ne 0 ]; then 677 error_exit $LINENO "An error occurred while attempting to start the service" 678 fi 679 } 680 681 # This will stop the launchd service 682 stop_launchd_service() 683 { 684 launchctl stop "com.observiq.${SERVICE_NAME}" >/dev/null 2>&1 || true 685 } 686 687 # This will configure the launcher to run as a service with sysv 688 create_sysv_service() 689 { 690 sysv_file="/etc/init.d/$SERVICE_NAME" 691 replace_service="false" 692 693 if [ -e "/etc/init.d/$SERVICE_NAME" ]; then 694 request_service_replacement 695 if [ $replace_service = "false" ]; then 696 return 0 697 fi 698 fi 699 700 info "Creating sevice file..." 701 create_sysv_file $sysv_file 702 chmod 755 $sysv_file 703 succeeded 704 705 706 info "Adding service..." 707 add_sysv_service 708 succeeded 709 710 if [ $replace_service = "true" ]; then 711 info "Restarting service..." 712 restart_sysv_service 713 succeeded 714 else 715 info "Starting service..." 716 start_sysv_service 717 succeeded 718 fi 719 720 startup_cmd="service $SERVICE_NAME start" 721 shutdown_cmd="service $SERVICE_NAME stop" 722 return 0 723 } 724 725 # This will create the sysv file used to run 726 # the agent as a service. 727 create_sysv_file() 728 { 729 cat << "EOF" > "$1" 730 #!/bin/sh 731 # carbon daemon 732 # chkconfig: 2345 99 05 733 # description: carbon log agent 734 # processname: REPLACE_AGENT_BINARY 735 # pidfile: /var/run/log-agent.pid 736 737 # Source function library. 738 if [ -e /etc/init.d/functions ]; then 739 STATUS=true 740 . /etc/init.d/functions 741 fi 742 743 if [ -e /lib/lsb/init-functions ]; then 744 PROC=true 745 . /lib/lsb/init-functions 746 fi 747 748 # Pull in sysconfig settings 749 [ -f /etc/sysconfig/log-agent ] && . /etc/sysconfig/log-agent 750 751 PROGRAM=log-agent 752 LOCKFILE=/var/lock/$PROGRAM 753 PIDFILE=/var/run/log-agent.pid 754 DEBUG=false 755 RETVAL=0 756 757 start() { 758 if [ -f $PIDFILE ]; then 759 PID=$(cat $PIDFILE) 760 echo " * $PROGRAM already running: $PID" 761 RETVAL=2 762 else 763 echo " * Starting $PROGRAM" 764 if [ -n "REPLACE_SERVICE_USER" ]; then 765 su -p REPLACE_SERVICE_USER -c "nohup REPLACE_AGENT_BINARY --log_file REPLACE_AGENT_LOG --database REPLACE_AGENT_DATABASE" > /dev/null 2>&1 & 766 else 767 nohup "REPLACE_AGENT_BINARY --log_file REPLACE_AGENT_LOG --database REPLACE_AGENT_DATABASE" > /dev/null 2>&1 & 768 fi 769 echo $! > $PIDFILE 770 RETVAL=$? 771 [ "$RETVAL" -eq 0 ] && touch $LOCKFILE 772 fi 773 } 774 775 stop() { 776 if [ -f $PIDFILE ]; then 777 PID=$(cat $PIDFILE); 778 printf " * Stopping $PROGRAM... " 779 kill $PID > /dev/null 2>&1 780 echo "stopped" 781 rm $PIDFILE && rm -f $LOCKFILE 782 RETVAL=0 783 else 784 echo " * $PROGRAM is not running" 785 RETVAL=3 786 fi 787 } 788 789 pid_status() { 790 if [ -e "$PIDFILE" ]; then 791 echo " * $PROGRAM" is running, pid=`cat "$PIDFILE"` 792 RETVAL=0 793 else 794 echo " * $PROGRAM is not running" 795 RETVAL=1 796 fi 797 } 798 799 agent_status() { 800 if [ $PROC ]; then 801 status_of_proc -p $PIDFILE "$PROGRAM" "$PROGRAM" 802 RETVAL=$? 803 elif [ $STATUS ]; then 804 status -p $PIDFILE $PROGRAM 805 RETVAL=$? 806 else 807 pid_status 808 fi 809 } 810 811 case "$1" in 812 start) 813 start 814 ;; 815 stop) 816 stop 817 ;; 818 status) 819 agent_status 820 ;; 821 restart) 822 stop 823 start 824 ;; 825 *) 826 echo "Usage: {start|stop|status|restart}" 827 RETVAL=3 828 ;; 829 esac 830 exit $RETVAL 831 EOF 832 sed -i "s|REPLACE_AGENT_HOME|$agent_home|" "$1" 833 sed -i "s|REPLACE_SERVICE_USER|$service_user|" "$1" 834 sed -i "s|REPLACE_AGENT_BINARY|$agent_binary|" "$1" 835 sed -i "s|REPLACE_AGENT_LOG|$agent_log|" "$1" 836 sed -i "s|REPLACE_AGENT_DATABASE|$agent_database|" "$1" 837 } 838 839 # This will load the sysv service. 840 add_sysv_service() 841 { 842 if command -v "chkconfig" > /dev/null ; then 843 chkconfig --add "$SERVICE_NAME" || error_exit "$LINENO" "Failed to install service" 844 elif command -v "update-rc.d" > /dev/null ; then 845 update-rc.d "$SERVICE_NAME" defaults 846 else 847 error "Could not find$fg_yellow chkconfig$fg_red or$fg_yellow update-rd.c$fg_red" 848 error "The agent has been extracted to $fg_blue$agent_home$fg_red and configured." 849 fi 850 } 851 852 # This will start the sysv service. It will fail 853 # and if unsuccessful. 854 start_sysv_service() 855 { 856 if ! output="$(service "$SERVICE_NAME" start 2>&1)"; then 857 error_exit "$LINENO" "Failed to start service:" "$output" 858 fi 859 } 860 861 # This will stop the sysv service if it is running 862 stop_sysv_service() 863 { 864 service "$SERVICE_NAME" stop >/dev/null 2>&1 || true 865 } 866 867 # This will restart the sysv service. It will fail 868 # and if unsuccessful. 869 restart_sysv_service() 870 { 871 if ! output="$(service "$SERVICE_NAME" restart 2>&1)"; then 872 error_exit "$LINENO" "Failed to start service:" "$output" 873 fi 874 } 875 876 # This will configure the launcher to run as a service with systemd 877 create_systemd_service() 878 { 879 systemd_file="/etc/systemd/system/$SERVICE_NAME.service" 880 replace_service="false" 881 882 if [ -e $systemd_file ]; then 883 request_service_replacement 884 if [ $replace_service = "false" ]; then 885 return 0 886 fi 887 fi 888 889 info "Creating service file..." 890 create_systemd_file $systemd_file 891 chmod 644 $systemd_file 892 succeeded 893 894 info "Reloading systemd configuration..." 895 systemctl daemon-reload || error_exit "$LINENO" "Failed to reload services" 896 succeeded 897 898 info "Enabling service..." 899 systemctl enable "$SERVICE_NAME.service" >/dev/null 2>&1 || error_exit "$LINENO" "Failed to enable service" 900 succeeded 901 902 if [ $replace_service = "true" ]; then 903 info "Restarting service..." 904 restart_systemd_service 905 succeeded 906 else 907 info "Starting service..." 908 start_systemd_service 909 succeeded 910 fi 911 912 shutdown_cmd="systemctl stop $SERVICE_NAME" 913 startup_cmd="systemctl start $SERVICE_NAME" 914 return 0 915 } 916 917 # This will create a systemd service file. The first argument 918 # represents the designated file location. 919 create_systemd_file() 920 { 921 cat << EOF > "$1" 922 [Unit] 923 Description=Carbon Log Agent 924 After=network.target 925 926 [Service] 927 Type=simple 928 PIDFile=/tmp/log-agent.pid 929 User=$service_user 930 Group=$service_user 931 Environment=PATH=/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin 932 WorkingDirectory=$agent_home 933 ExecStart=$agent_binary --log_file $agent_log --database $agent_database 934 SuccessExitStatus=143 935 TimeoutSec=0 936 StandardOutput=null 937 938 [Install] 939 WantedBy=multi-user.target 940 EOF 941 } 942 943 # This will start the systemd service. It will fail 944 # and disable the service if unsuccessful. 945 start_systemd_service() 946 { 947 if ! systemctl start "$SERVICE_NAME.service"; then 948 error "Failed to start $SERVICE_NAME.service. Disabling $SERVICE_NAME.service." 949 systemctl disable "$SERVICE_NAME.service" 950 error_exit "$LINENO" "Failed to start service" 951 fi 952 } 953 954 # This will stop the systemd service if it is running 955 stop_systemd_service() 956 { 957 systemctl stop "$SERVICE_NAME.service" >/dev/null 2>&1 || true 958 } 959 960 # This will restart the systemd service. It will fail 961 # if unsuccessful. 962 restart_systemd_service() 963 { 964 systemctl restart "$SERVICE_NAME.service" || error_exit "$LINENO" "Failed to restart service" 965 } 966 967 # This will notify the user that a service already exists 968 # and will await their response on replacing the service 969 request_service_replacement() 970 { 971 command printf "${indent}Service '$(fg_cyan $SERVICE_NAME)' already exists. Replace it? $(prompt)" 972 read -r replace_service_response 973 case $replace_service_response in 974 n|N|no|No|NO) 975 warn "Skipping service creation!" 976 replace_service="false" 977 ;; 978 *) 979 increase_indent 980 success "Replacing service!" 981 decrease_indent 982 replace_service="true" 983 ;; 984 esac 985 } 986 987 # This will display the results of an installation 988 display_results() 989 { 990 banner 'Information' 991 increase_indent 992 info "Carbon Home: $(fg_cyan "$agent_home")$(reset)" 993 info "Carbon Config: $(fg_cyan "$agent_home/config.yaml")$(reset)" 994 info "Start Command: $(fg_cyan "$startup_cmd")$(reset)" 995 info "Stop Command: $(fg_cyan "$shutdown_cmd")$(reset)" 996 decrease_indent 997 998 banner "$(fg_green Installation Complete!)" 999 return 0 1000 } 1001 1002 main() 1003 { 1004 if [ $# -ge 1 ]; then 1005 while [ -n "$1" ]; do 1006 case "$1" in 1007 -y|--accept-defaults) 1008 accept_defaults="yes" ; shift 1 ;; 1009 -v|--version) 1010 version=$2 ; shift 2 ;; 1011 -i|--install-dir) 1012 install_dir=$2 ; shift 2 ;; 1013 -u|--service-user) 1014 service_user=$2 ; shift 2 ;; 1015 -h|--help) 1016 usage 1017 force_exit 1018 ;; 1019 --) 1020 shift; break ;; 1021 *) 1022 error "Invalid argument: $1" 1023 usage 1024 force_exit 1025 ;; 1026 esac 1027 done 1028 fi 1029 1030 check_prereqs 1031 setup_installation 1032 install_package 1033 generate_config 1034 install_service 1035 display_results 1036 } 1037 1038 main "$@"