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 "$@"