MacPortsFramework: install_script_agent7 2.sh

File install_script_agent7 2.sh, 75.6 KB (added by W3W-EdU (Karam Jameel Moore), 5 months ago)
Line 
1#!/bin/bash
2# (C) Datadog, Inc. 2010-present
3# All rights reserved
4# Licensed under Apache-2.0 License (see LICENSE)
5# Datadog Agent installation script: install and set up the Agent on supported Linux distributions
6# using the package manager and Datadog repositories.
7
8set -e
9
10
11
12install_script_version=1.35.4
13logfile="ddagent-install.log"
14support_email=support@datadoghq.com
15variant=install_script_agent7
16
17LEGACY_ETCDIR="/etc/dd-agent"
18LEGACY_CONF="$LEGACY_ETCDIR/datadog.conf"
19
20# DATADOG_APT_KEY_CURRENT.public always contains key used to sign current
21# repodata and newly released packages
22# DATADOG_APT_KEY_382E94DE.public expires in 2022
23# DATADOG_APT_KEY_F14F620E.public expires in 2032
24# DATADOG_APT_KEY_C0962C7D.public expires in 2028
25# DATADOG_APT_KEY_06462314.public expires in 2033
26APT_GPG_KEYS=("DATADOG_APT_KEY_CURRENT.public" "DATADOG_APT_KEY_06462314.public" "DATADOG_APT_KEY_C0962C7D.public" "DATADOG_APT_KEY_F14F620E.public" "DATADOG_APT_KEY_382E94DE.public")
27
28# DATADOG_RPM_KEY_CURRENT.public always contains key used to sign current
29# repodata and newly released packages
30# DATADOG_RPM_KEY_E09422B3.public expires in 2022
31# DATADOG_RPM_KEY_FD4BF915.public expires in 2024
32# DATADOG_RPM_KEY_B01082D3.public expires in 2028
33# DATADOG_RPM_KEY_4F09D16B.public expires in 2033
34RPM_GPG_KEYS=("DATADOG_RPM_KEY_CURRENT.public" "DATADOG_RPM_KEY_4F09D16B.public" "DATADOG_RPM_KEY_B01082D3.public" "DATADOG_RPM_KEY_FD4BF915.public" "DATADOG_RPM_KEY_E09422B3.public")
35
36# DATADOG_RPM_KEY.public (4172A230) was only useful to install old (< 6.14) Agent packages.
37# We no longer add it and we explicitly remove it.
38RPM_GPG_KEYS_TO_REMOVE=("gpg-pubkey-4172a230-55dd14f6")
39
40# Error codes for telemetry
41GENERAL_ERROR_CODE=1
42UNSUPPORTED_PLATFORM_CODE=5
43INVALID_PARAMETERS_CODE=6
44UNABLE_TO_INSTALL_DEPENDENCY_CODE=7
45
46# Set up a named pipe for logging
47npipe=/tmp/$$.tmp
48mknod $npipe p
49
50# Log all output to a log for error checking
51tee <$npipe $logfile &
52exec 1>&-
53exec 1>$npipe 2>&1
54trap 'rm -f $npipe' EXIT
55
56##
57# REPORTING AND COMMON METHODS
58##
59function fallback_msg(){
60  printf "
61If you are still having problems, please send an email to $support_email
62with the contents of $logfile and any information you think would be
63useful and we will do our very best to help you solve your problem.\n"
64}
65
66function report(){
67  if curl -f -sSL --retry 5 \
68    --data-urlencode "os=${OS}" \
69    --data-urlencode "version=${agent_major_version}" \
70    --data-urlencode "log=$(cat $logfile)" \
71    --data-urlencode "email=${email}" \
72    --data-urlencode "apikey=${apikey}" \
73    --data-urlencode "variant=${variant}" \
74    "$report_failure_url"; then
75   printf "A notification has been sent to Datadog with the contents of $logfile\n"
76  else
77    printf "Unable to send the notification (curl v7.18 or newer is required)"
78  fi
79}
80
81function report_telemetry() {
82  local install_id="$1"
83  local install_type="$2"
84  local install_time="$3"
85
86  if [ "$DD_INSTRUMENTATION_TELEMETRY_ENABLED" == "false" ] || \
87    [ "$site" == "ddog-gov.com" ] || \
88    [ -z "${apikey}" ] || \
89    [ -z "$telemetry_url" ]; then
90    return
91  fi
92
93  install_id_tag=
94  install_type_tag=
95  install_time_tag=
96  if [ -n "$install_id" ] ; then
97    install_id_tag="\"install_id\": \"$install_id\","
98  fi
99  if [ -n "$install_type" ] ; then
100    install_type_tag="\"install_type\": \"$install_type\","
101  fi
102  if [ -n "$install_time" ] ; then
103    install_time_tag="\"install_time\": $install_time,"
104  fi
105
106  if [ -n "$agent_minor_version" ] ; then
107    safe_agent_version=$(echo -n "$agent_major_version.$agent_minor_version" | tr '\n' ' ' | tr '"' '_')
108  else
109    safe_agent_version=$(echo -n "$agent_major_version" | tr '\n' ' ' | tr '"' '_')
110  fi
111
112  library_telemetry_info=
113
114  if [ ${#apm_libraries[@]} -gt 0 ]; then
115    for lib in "${apm_libraries[@]}"
116    do
117      cur_lib=$(echo "$lib" | cut -s -d':' -f1)
118      cur_version=$(echo "$lib" | cut -s -d':' -f2)
119      if [ -z "$cur_version" ] ; then
120        cur_version="default"
121        cur_lib="$lib"
122      fi
123      case $cur_lib in
124        datadog-apm-library-java)
125          library_telemetry_info="${library_telemetry_info},\"specified_java_lib_version\": \"${cur_version}\""
126          ;;
127        datadog-apm-library-js)
128          library_telemetry_info="${library_telemetry_info},\"specified_nodejs_lib_version\": \"${cur_version}\""
129          ;;
130        datadog-apm-library-python)
131          library_telemetry_info="${library_telemetry_info},\"specified_python_lib_version\": \"${cur_version}\""
132          ;;
133        datadog-apm-library-dotnet)
134          library_telemetry_info="${library_telemetry_info},\"specified_dotnet_lib_version\": \"${cur_version}\""
135          ;;
136        datadog-apm-library-ruby)
137          library_telemetry_info="${library_telemetry_info},\"specified_ruby_lib_version\": \"${cur_version}\""
138          ;;
139        datadog-apm-library-php)
140          library_telemetry_info="${library_telemetry_info},\"specified_php_lib_version\": \"${cur_version}\""
141          ;;
142        *)
143          ;;
144      esac
145    done
146  fi
147
148 
149  if [ -z "${ERROR_CODE}" ] ; then
150    telemetry_event="
151{
152   \"request_type\": \"apm-onboarding-event\",
153   \"api_version\": \"v1\",
154   \"payload\": {
155       \"event_name\": \"agent.installation.success\",
156       \"tags\": {
157           $install_id_tag
158           $install_type_tag
159           $install_time_tag
160           \"agent_platform\": \"native\",
161           \"agent_version\": \"$safe_agent_version\",
162           \"script_version\": \"$install_script_version\" $library_telemetry_info
163       }
164   }
165}
166"
167  else
168    safe_error_message=$(echo -n "$ERROR_MESSAGE" | tr '\n' ' ' | tr '"' '_')
169    # Install ID, time and type are typically not reported if the installation does not succeed,
170    # but if the function is called with those arguments, we will pass them along anyway.
171    telemetry_event="
172{
173   \"request_type\": \"apm-onboarding-event\",
174   \"api_version\": \"v1\",
175   \"payload\": {
176       \"event_name\": \"agent.installation.error\",
177       \"tags\": {
178           $install_id_tag
179           $install_type_tag
180           $install_time_tag
181           \"agent_platform\": \"native\",
182           \"agent_version\": \"$safe_agent_version\",
183           \"script_version\": \"$install_script_version\" $library_telemetry_info
184       },
185       \"error\": {
186          \"code\": $ERROR_CODE,
187          \"message\": \"$safe_error_message\"
188       }
189   }
190}
191"
192  fi
193
194  if ! (cat <<END
195       $telemetry_event
196END
197       ) | curl -f -sSL --retry 5 -o /dev/null \
198    "$telemetry_url" \
199    --header 'Content-Type: application/json' \
200    --header "DD-Api-Key: $apikey" \
201    --data @-
202  then
203    printf "Unable to send telemetry\n"
204  fi
205}
206
207function on_read_error() {
208  printf "Timed out or input EOF reached, assuming 'No'\n"
209  yn="n"
210}
211
212function get_email() {
213  emaillocalpart='^[a-zA-Z0-9][a-zA-Z0-9._%+-]{0,63}'
214  hostnamepart='[a-zA-Z0-9.-]+\.[a-zA-Z]+'
215  email_regex="$emaillocalpart@$hostnamepart"
216  cntr=0
217  until [[ "$cntr" -eq 3 ]]
218  do
219      read -p "Enter an email address so we can follow up: " -r email
220      if [[ "$email" =~ $email_regex ]]; then
221        isEmailValid=true
222        break
223      else
224        ((cntr=cntr+1))
225        echo -e "\033[33m($cntr/3) Email address invalid: $email\033[0m\n"
226      fi
227  done
228}
229
230function on_error() {
231    if [ -z "${ERROR_MESSAGE}" ] ; then
232      # Save the few lines of the log file for telemetry if the error message is blank
233      SAVED_ERROR_MESSAGE=$(tail -n 3 $logfile)
234    fi
235
236    printf "\033[31m$ERROR_MESSAGE
237It looks like you hit an issue when trying to install the $nice_flavor.
238
239    $ERR_SUMMARY
240
241Troubleshooting and basic usage information for the $nice_flavor are available at:
242
243    https://docs.datadoghq.com/agent/basic_agent_usage/\n\033[0m\n"
244
245    ERROR_MESSAGE=$SAVED_ERROR_MESSAGE
246    ERROR_CODE=$GENERAL_ERROR_CODE
247    report_telemetry
248
249    if ! tty -s; then
250      fallback_msg
251      exit 1;
252    fi
253
254    if [ "$site" == "ddog-gov.com" ]; then
255      fallback_msg
256      exit 1;
257    fi
258
259    while true; do
260        read -t 60 -p  "Do you want to send a failure report to Datadog (including $logfile)? (y/[n]) " -r yn || on_read_error
261        case $yn in
262          [Yy]* )
263            get_email
264            if [[ -n "$isEmailValid" ]]; then
265              report
266            fi
267            fallback_msg
268            break;;
269          [Nn]*|"" )
270            fallback_msg
271            break;;
272          * )
273            printf "Please answer yes or no.\n"
274            ;;
275        esac
276    done
277}
278trap on_error ERR
279
280function verify_agent_version(){
281    local ver_separator="$1"
282    if [ -z "$agent_version_custom" ]; then
283        ERROR_MESSAGE="Specified version not found: $agent_major_version.$agent_minor_version"
284        ERROR_CODE=$INVALID_PARAMETERS_CODE
285        echo -e "
286  \033[33mWarning: $ERROR_MESSAGE
287  Check available versions at: https://github.com/DataDog/datadog-agent/blob/main/CHANGELOG.rst\033[0m"
288        fallback_msg
289        report_telemetry
290        exit 1;
291    else
292        agent_flavor+="$ver_separator$agent_version_custom"
293    fi
294}
295
296function remove_rpm_gpg_keys() {
297    local sudo_cmd="$1"
298    shift
299    local old_keys=("$@")
300    for key in "${old_keys[@]}"; do
301        if $sudo_cmd rpm -q "$key" 1>/dev/null 2>/dev/null; then
302            echo -e "\033[34m\nRemoving old RPM key $key from the RPM database\n\033[0m"
303            $sudo_cmd rpm --erase "$key"
304        fi
305    done
306}
307
308# Emulate hashmap with simple switch case
309function getMapData() {
310
311    if [ "$1" = "flavor_to_readable" ]; then
312        case "$2" in
313            "datadog-agent")
314                DATA="Datadog Agent"
315                ;;
316             "datadog-iot-agent")
317                DATA="Datadog IoT Agent"
318                ;;
319             "datadog-dogstatsd")
320                DATA="Datadog Dogstatsd"
321                ;;
322             "datadog-fips-proxy")
323                DATA="Datadog FIPS Proxy"
324                ;;
325             "datadog-heroku-agent")
326                DATA="Datadog Heroku Agent"
327                ;;
328             "datadog-installer")
329                DATA="Datadog Installer"
330                ;;
331              *)
332                DATA="Unknown"
333                ;;
334         esac
335    fi
336    printf '%s' "$DATA"
337}
338
339# Create a configuration file with proper ownership and permission if it doesn't already exist
340function ensure_config_file_exists() {
341    local sudo_cmd="$1"
342    local config_file="$2"
343    local owner="$3"
344
345    if [ -e "$config_file" ]; then
346        printf "\033[34m\n* Keeping old $config_file configuration file\n\033[0m\n"
347        return 1
348    else
349        $sudo_cmd cp "$config_file.example" "$config_file"
350        cp_res=$?
351        $sudo_cmd chown "$owner:dd-agent" "$config_file"
352        chown_res=$?
353        $sudo_cmd chmod 640 "$config_file"
354        chmod_res=$?
355        return $((cp_res + chown_res + chmod_res))
356    fi
357}
358
359function json_escape() {
360    local string="$1"
361    # Escape characters that are special to JSON
362    string="${string//\\/\\\\}"  # Escape backslash
363    string="${string//\"/\\\"}"  # Escape double quote
364    string="${string//$'\t'/\\t}"  # Escape tab
365    string="${string//$'\n'/\\n}"  # Escape newline
366    string="${string//$'\r'/\\r}"  # Escape carriage return
367    string="${string//$'\b'/\\b}"  # Escape backspace
368    string="${string//$'\f'/\\f}"  # Escape form feed
369    echo "$string"
370}
371
372function report_installer_telemetry() {
373    local trace_id="$1"
374    local os="$2"
375    local distribution="$3"
376    local start_time="$4"
377    local exit_code="$5"
378    local install_stdout="$6"
379    local install_stderr="$7"
380    local packages_to_install="$8"
381    local packages_to_install_after_installer="$9"
382
383    install_stdout=$(json_escape "$install_stdout")
384    install_stderr=$(json_escape "$install_stderr")
385
386    local time_now_seconds
387    local time_now
388    local time_since_start
389    local json_logs
390    local telemetry_trace
391    local telemetry_logs
392
393    if [ "$DD_INSTRUMENTATION_TELEMETRY_ENABLED" == "false" ] || \
394      [ "$site" == "ddog-gov.com" ] || \
395      [ -z "${apikey}" ] || \
396      [ -z "$telemetry_url" ]; then
397      return
398    fi
399
400    time_now_seconds=$(date +%s)
401    time_now=$(date +%s%N)
402    time_since_start=$((time_now - start_time))
403
404    telemetry_trace=$(cat <<-END
405    {
406        "api_version": "v2",
407        "request_type": "traces",
408        "tracer_time": ${time_now_seconds},
409        "runtime_id": "${trace_id}",
410        "seq_id": 1,
411        "origin": "linux-install-script",
412        "host": {
413            "hostname": "$(json_escape "$(uname -n)")",
414            "os": "$(json_escape "${os}")",
415            "distribution": "$(json_escape "${distribution}")",
416            "architecture": "$(json_escape "$(uname -m)")",
417            "kernel_version": "$(json_escape "$(uname -v)")",
418            "kernel_name": "$(json_escape "$(uname -s)")",
419            "kernel_release": "$(json_escape "$(uname -r)")"
420        },
421        "application": {
422            "service_name": "datadog-linux-install-script",
423            "service_version": "${install_script_version}",
424            "language_name": "UNKNOWN",
425            "language_version": "n/a",
426            "tracer_version": "n/a"
427        },
428        "payload": {
429            "traces": [[
430                {
431                    "service": "datadog-linux-install-script",
432                    "name": "install_installer",
433                    "resource": "install_installer",
434                    "trace_id": ${trace_id},
435                    "span_id": ${trace_id},
436                    "parent_id": 0,
437                    "start": ${start_time},
438                    "duration": ${time_since_start},
439                    "error": ${exit_code},
440                    "meta": {
441                        "language": "shell",
442                        "exit_code": ${exit_code},
443                        "error.message": "${install_stderr}",
444                        "version": "${install_script_version}",
445                        "packages_to_install": "$(json_escape "${packages_to_install}")",
446                        "packages_to_install_after_installer": "$(json_escape "${packages_to_install_after_installer}")",
447                        "network.gcr_io": "$(json_escape "$(curl -I --max-time 5 -s -o /dev/null -w "%{http_code}" "https://gcr.io/v2/datadoghq/installer-package/manifests/latest")")",
448                        "network.install_datadoghq_com_install_script": "$(json_escape "$(curl -I --max-time 5 -s -o /dev/null -w "%{http_code}" "https://install.datadoghq.com/scripts/install_script_agent7.sh")")",
449                        "network.install_datadoghq_com_index": "$(json_escape "$(curl -I --max-time 5 -s -o /dev/null -w "%{http_code}" "https://install.datadoghq.com/index.html")")",
450                        "network.public_ecr_aws": "$(json_escape "$(curl -I --max-time 5 -s -o /dev/null -w "%{http_code}" "https://public.ecr.aws/datadog/agent/manifests/latest")")",
451                        "network.yum_datadoghq_com": "$(json_escape "$(curl -I --max-time 5 -s -o /dev/null -w "%{http_code}" "https://yum.datadoghq.com/index.html")")",
452                        "network.apt_datadoghq_com": "$(json_escape "$(curl -I --max-time 5 -s -o /dev/null -w "%{http_code}" "https://apt.datadoghq.com/index.html")")"
453                    },
454                    "metrics": {
455                        "_trace_root": 1,
456                        "_top_level": 1,
457                        "_dd.top_level": 1,
458                        "_sampling_priority_v1": 2
459                    }
460                }
461            ]]
462        }
463    }
464END
465)
466
467    json_logs="[{\"message\": \"$install_stdout\", \"level\": \"DEBUG\", \"trace_id\": \"${trace_id}\", \"span_id\": \"${trace_id}\"}, {\"message\": \"$install_stderr\", \"level\": \"ERROR\", \"trace_id\": \"${trace_id}\", \"span_id\": \"${trace_id}\"}]"
468
469    telemetry_logs=$(cat <<-END
470    {
471        "api_version": "v2",
472        "request_type": "logs",
473        "tracer_time": ${time_now_seconds},
474        "runtime_id": "${trace_id}",
475        "seq_id": 2,
476        "origin": "linux-install-script",
477        "host": {
478            "hostname": "$(json_escape "$(uname -n)")",
479            "os": "$(json_escape "${os}")",
480            "distribution": "$(json_escape "${distribution}")",
481            "architecture": "$(json_escape "$(uname -m)")",
482            "kernel_version": "$(json_escape "$(uname -v)")",
483            "kernel_name": "$(json_escape "$(uname -s)")",
484            "kernel_release": "$(json_escape "$(uname -r)")"
485        },
486        "application": {
487            "service_name": "datadog-linux-install-script",
488            "service_version": "${install_script_version}",
489            "language_name": "UNKNOWN",
490            "language_version": "n/a",
491            "tracer_version": "n/a"
492        },
493        "payload": {
494            "logs": ${json_logs}
495        }
496    }
497END
498)
499
500    if ! echo "$telemetry_logs" | curl --max-time 10 -f -sSL --retry 5 -o /dev/null \
501        "$telemetry_url" \
502        --header 'Content-Type: application/json' \
503        --header "DD-Api-Key: $apikey" \
504        --data @-
505    then
506        echo "Unable to send logs telemetry\n"
507    fi
508
509    if ! echo "$telemetry_trace" | curl --max-time 10 -f -sSL --retry 5 -o /dev/null \
510    "$telemetry_url" \
511    --header 'Content-Type: application/json' \
512    --header "DD-Api-Key: $apikey" \
513    --data @-
514    then
515        echo "Unable to send trace telemetry\n"
516    fi
517    echo "$telemetry_trace" | $sudo_cmd tee /tmp/datadog-installer-trace.json
518}
519
520function _install_installer() {
521    local sudo_cmd="$1"
522    local os="$2"
523    local distribution="$3"
524
525    local command_prefix
526
527    if [ "$os" == "Debian" ]; then
528        echo -e "\033[34m\n* Installing the Datadog installer\n\033[0m"
529        $sudo_cmd apt-get install -o Acquire::Retries="5" -y --force-yes "datadog-installer" || return $?
530    elif [ "$os" == "Red Hat" ]; then
531        echo -e "\033[34m\n* Installing the Datadog installer\n\033[0m"
532        $sudo_cmd yum -y --disablerepo='*' --enablerepo='datadog' install "datadog-installer" || $sudo_cmd yum -y install "datadog-installer" || return $?
533    elif [ "$os" == "SUSE" ]; then
534        echo -e "\033[34m\n* Installing the Datadog installer\n\033[0m"
535        $sudo_cmd zypper --non-interactive --no-refresh install "datadog-installer" || return $?
536    else
537        return 0
538    fi
539    command_prefix="${sudo_cmd:+$sudo_cmd -E}"
540    $command_prefix sh -c "DD_API_KEY=\"${apikey}\" DD_SITE=\"${site}\" DD_REMOTE_POLICIES=\"${remote_policies}\" DD_REMOTE_UPDATES=\"${remote_updates}\" DATADOG_TRACE_ID=\"${trace_id}\" DATADOG_PARENT_ID=\"${trace_id}\" /usr/bin/datadog-bootstrap bootstrap"
541    return $?
542}
543
544function is_installed_by_installer() {
545    local sudo_cmd="$1"
546    local package="$2"
547    local command_prefix
548    if command -v datadog-installer >/dev/null 2>&1; then
549        command_prefix="${sudo_cmd:+$sudo_cmd -E}"
550        $command_prefix sh -c "DD_API_KEY=\"${apikey}\" DD_SITE=\"${site}\" DATADOG_TRACE_ID=\"${trace_id}\" DATADOG_PARENT_ID=\"${trace_id}\" datadog-installer is-installed \"${package}\""
551        local status=$?
552        if [ $status -eq 0 ]; then
553            return 0
554        elif [ $status -eq 10 ]; then # 10 means the package is not installed
555            return 1
556        else
557            return $status
558        fi
559    else
560        return 1
561    fi
562}
563
564function filter_packages_installed_by_installer() {
565    local sudo_cmd="$1"
566    local pkg_array_name=$2
567    local -a not_installed_packages=()  # Temporary array for not installed packages
568
569    for package in $(eval echo "\${${pkg_array_name}[@]}"); do
570        if ! is_installed_by_installer "$sudo_cmd" "$package"; then
571            not_installed_packages+=("$package")
572        else
573            echo -e "\033[34m\n* $package has been installed successfully by the installer\n\033[0m"
574        fi
575    done
576
577    # Copy the filtered array back to the original array
578    eval "$pkg_array_name=(\"\${not_installed_packages[@]}\")"
579}
580
581# Install the Datadog installer package
582function install_installer() {
583    local sudo_cmd="$1"
584    local os="$2"
585    local distribution="$3"
586    local datadog_installer="$4"
587    local remote_updates="$5"
588    local apm_instrumentation_enabled="$6"
589    local pkg_array_name="$7"
590
591    local trace_id
592    local start_time
593    local install_stdout
594    local install_stderr
595    local exit_status
596
597    # The installer is currently only being rolled out to APM instrumentation users
598    if [ -z "$apm_instrumentation_enabled" ] && [ -z "$datadog_installer" ] && [ -z "$remote_updates" ]; then
599        return 0
600    fi
601
602    trace_id=$(od -An -N8 -tu8 < /dev/urandom | tr -d ' ')
603    start_time=$(date +%s%N)
604
605    (_install_installer "$sudo_cmd" "$os" "$distribution" > /tmp/datadog-installer-stdout.log 2> /tmp/datadog-installer-stderr.log) || exit_status=$?
606    exit_status=${exit_status:-0}
607
608    local packages_to_install
609    local packages_to_install_after_installer
610
611    packages_to_install=("${!pkg_array_name}")
612    filter_packages_installed_by_installer "$sudo_cmd" "$pkg_array_name"
613    packages_to_install_after_installer=("${!pkg_array_name}")
614
615    install_stdout=$(cat /tmp/datadog-installer-stdout.log)
616    install_stderr=$(cat /tmp/datadog-installer-stderr.log)
617    (report_installer_telemetry "$trace_id" "$os" "$distribution" "$start_time" "$exit_status" "$install_stdout" "$install_stderr" "${packages_to_install[*]}" "${packages_to_install_after_installer[*]}") || true
618    if [ $exit_status -ne 0 ] && ([ -n "$datadog_installer" ] || [ -n "$remote_updates" ]); then
619        echo -e "\033[31m\n* Failed to install the Datadog installer\n\033[0m"
620        echo "$install_stderr"
621        exit $exit_status
622    fi
623    return $exit_status
624}
625
626echo -e "\033[34m\n* Datadog Agent 7 install script v${install_script_version}\n\033[0m"
627
628##
629# AGENT CONFIGURATION OPTIONS
630# They are only considered if the configuration file does not already exist (call to `ensure_config_file_exist`)
631##
632hostname=
633if [ -n "$DD_HOSTNAME" ]; then
634    hostname=$DD_HOSTNAME
635fi
636
637site=
638if [ -n "$DD_SITE" ]; then
639    site="$DD_SITE"
640fi
641
642apikey=
643if [ -n "$DD_API_KEY" ]; then
644    apikey=$DD_API_KEY
645fi
646
647no_start=
648if [ -n "$DD_INSTALL_ONLY" ]; then
649    no_start=true
650    # When installing rpm packages, scripts might try to start the service
651    # which we want to avoid
652    SYSTEMD_OFFLINE=1
653fi
654
655no_agent=
656if [ -n "$DD_NO_AGENT_INSTALL" ]; then
657    no_agent=true
658fi
659
660host_tags=  # A comma-separated list of tags, e.g. foo:bar,env:prod
661if [ -n "$DD_TAGS" ]; then
662    host_tags=$DD_TAGS
663    # Falling back to the deprecated DD_HOST_TAGS if DD_TAGS is not set
664elif [ -n "$DD_HOST_TAGS" ]; then
665    host_tags=$DD_HOST_TAGS
666fi
667
668if [ -n "$DD_REPO_URL" ]; then
669    repository_url=$DD_REPO_URL
670elif [ -n "$REPO_URL" ]; then
671    echo -e "\033[33mWarning: REPO_URL is deprecated and might be removed later (use DD_REPO_URL instead).\033[0m"
672    repository_url=$REPO_URL
673else
674    repository_url="datadoghq.com"
675fi
676
677upgrade=
678if [ -n "$DD_UPGRADE" ]; then
679  upgrade=$DD_UPGRADE
680fi
681
682fips_mode=
683if [ -n "$DD_FIPS_MODE" ]; then
684  fips_mode=$DD_FIPS_MODE
685fi
686
687dd_env=
688if [ -n "$DD_ENV" ]; then
689    dd_env=$DD_ENV
690fi
691
692system_probe_ensure_config=
693if [ -n "$DD_SYSTEM_PROBE_ENSURE_CONFIG" ]; then
694  system_probe_ensure_config=$DD_SYSTEM_PROBE_ENSURE_CONFIG
695fi
696
697agent_flavor="datadog-agent"
698if [ -n "$DD_AGENT_FLAVOR" ]; then
699    agent_flavor=$DD_AGENT_FLAVOR #Eg: datadog-iot-agent
700fi
701
702datadog_installer=
703if [ -n "$DD_INSTALLER" ]; then
704    datadog_installer=true
705fi
706
707remote_updates=
708if [ -n "$DD_REMOTE_UPDATES" ]; then
709    remote_updates=$DD_REMOTE_UPDATES
710fi
711
712remote_policies=
713if [ -n "$DD_REMOTE_POLICIES" ]; then
714    remote_policies=$DD_REMOTE_POLICIES
715fi
716
717installer_registry_url=
718if [ -n "$DD_INSTALLER_REGISTRY_URL" ]; then
719    installer_registry_url=$DD_INSTALLER_REGISTRY_URL
720fi
721
722installer_registry_auth=
723if [ -n "$DD_INSTALLER_REGISTRY_AUTH" ]; then
724    installer_registry_auth=$DD_INSTALLER_REGISTRY_AUTH
725fi
726
727##
728# INSTALL SCRIPT CONFIGURATION OPTIONS
729# Technical options to test with non-production values for signature keys, packages or reporting telemetry.
730##
731if [ -n "$TESTING_KEYS_URL" ]; then
732  keys_url=$TESTING_KEYS_URL
733else
734  keys_url="keys.datadoghq.com"
735fi
736
737if [ -n "$TESTING_YUM_URL" ]; then
738  yum_url=$TESTING_YUM_URL
739else
740  yum_url="yum.${repository_url}"
741fi
742
743# We turn off `repo_gpgcheck` for custom REPO_URL, unless explicitly turned
744# on via DD_RPM_REPO_GPGCHECK.
745# There is more logic for redhat/suse in their specific code branches below
746rpm_repo_gpgcheck=
747if [ -n "$DD_RPM_REPO_GPGCHECK" ]; then
748    rpm_repo_gpgcheck=$DD_RPM_REPO_GPGCHECK
749else
750    if [ -n "$REPO_URL" ] || [ -n "$DD_REPO_URL" ]; then
751        rpm_repo_gpgcheck=0
752    fi
753fi
754
755if [ -n "$TESTING_APT_URL" ]; then
756  apt_url=$TESTING_APT_URL
757else
758  apt_url="apt.${repository_url}"
759fi
760
761report_failure_url="https://api.datadoghq.com/agent_stats/report_failure"
762if [ -n "$DD_SITE" ]; then
763    report_failure_url="https://api.${DD_SITE}/agent_stats/report_failure"
764fi
765
766telemetry_url="https://instrumentation-telemetry-intake.datadoghq.com/api/v2/apmtelemetry"
767if [ -n "$DD_SITE" ]; then
768    telemetry_url="https://instrumentation-telemetry-intake.${DD_SITE}/api/v2/apmtelemetry"
769fi
770
771if [ -n "$TESTING_REPORT_URL" ]; then
772  report_failure_url=$TESTING_REPORT_URL
773  telemetry_url=$TESTING_REPORT_URL
774fi
775
776##
777# APM SPECIFIC CONFIGURATION
778##
779declare -a apm_libraries
780declare host_injection_enabled
781declare docker_injection_enabled
782install_type="linux_agent_installer"
783
784
785if [ "$DD_APM_INSTRUMENTATION_ENABLED" = "all" ] ; then
786  host_injection_enabled="true"
787  docker_injection_enabled="true"
788  install_type="linux_single_step_all"
789fi
790
791if [ "$DD_APM_INSTRUMENTATION_ENABLED" = "host" ] ; then
792  host_injection_enabled="true"
793  install_type="linux_single_step_hst"
794fi
795
796if [ "$DD_APM_INSTRUMENTATION_ENABLED" = "docker" ] ; then
797  docker_injection_enabled="true"
798  install_type="linux_single_step_dkr"
799  no_agent=true
800fi
801
802if [ -n "${host_injection_enabled}${docker_injection_enabled}" ] ; then
803    apm_libraries=("datadog-apm-inject")
804fi
805
806if [ -n "$DD_APM_INSTRUMENTATION_LIBRARIES" ]; then
807  read -r -a lib_array <<< "$(echo "$DD_APM_INSTRUMENTATION_LIBRARIES" | tr , ' ')"
808  for lib in "${lib_array[@]}"
809  do
810    cur_lib=$(echo "$lib" | cut -s -d':' -f1)
811    cur_version=$(echo "$lib" | cut -s -d':' -f2)
812    if [ -z "$cur_lib" ] ; then
813      cur_lib="$lib"
814    elif [ "$cur_version" = "latest" ] ; then
815      cur_version=""
816    else
817      cur_version=":${cur_version}-1"
818    fi
819    case $cur_lib in
820      all)
821        apm_libraries+=("datadog-apm-library-java" "datadog-apm-library-js" "datadog-apm-library-python" "datadog-apm-library-dotnet" "datadog-apm-library-ruby") # php is not installed by default yet
822        ;;
823      java)
824        apm_libraries+=("datadog-apm-library-java${cur_version}")
825        ;;
826      js)
827        apm_libraries+=("datadog-apm-library-js${cur_version}")
828        ;;
829      python)
830        apm_libraries+=("datadog-apm-library-python${cur_version}")
831        ;;
832      dotnet)
833        apm_libraries+=("datadog-apm-library-dotnet${cur_version}")
834        ;;
835      ruby)
836        apm_libraries+=("datadog-apm-library-ruby${cur_version}")
837        ;;
838      php)
839        apm_libraries+=("datadog-apm-library-php${cur_version}")
840        ;;
841      *)
842        ERROR_MESSAGE="Unknown apm library: $cur_lib. Must be one of: all, java, js, python, dotnet, ruby, php"
843        ERROR_CODE=$INVALID_PARAMETERS_CODE
844        echo "$ERROR_MESSAGE"
845        report_telemetry
846        exit 1;
847        ;;
848    esac
849  done
850elif [ -n "$DD_APM_INSTRUMENTATION_LANGUAGES" ]; then
851  read -r -a lib_array <<< "$DD_APM_INSTRUMENTATION_LANGUAGES"
852  for lib in "${lib_array[@]}"
853  do
854    case $lib in
855      all)
856        apm_libraries+=("datadog-apm-library-java" "datadog-apm-library-js" "datadog-apm-library-python" "datadog-apm-library-dotnet" "datadog-apm-library-ruby") # php is not installed by default yet
857        ;;
858      java)
859        apm_libraries+=("datadog-apm-library-java")
860        ;;
861      js)
862        apm_libraries+=("datadog-apm-library-js")
863        ;;
864      python)
865        apm_libraries+=("datadog-apm-library-python")
866        ;;
867      dotnet)
868        apm_libraries+=("datadog-apm-library-dotnet")
869        ;;
870      ruby)
871        apm_libraries+=("datadog-apm-library-ruby")
872        ;;
873      php)
874        apm_libraries+=("datadog-apm-library-php")
875        ;;
876      *)
877        ERROR_MESSAGE="Unknown apm library: $lib. Must be one of: all, java, js, python, dotnet, ruby, php"
878        ERROR_CODE=$INVALID_PARAMETERS_CODE
879        echo "$ERROR_MESSAGE"
880        report_telemetry
881        exit 1;
882        ;;
883    esac
884  done
885elif [ -n "$host_injection_enabled" ] || [ -n "$docker_injection_enabled" ]; then
886  # Default to all libraries if injection is enabled
887  apm_libraries+=("datadog-apm-library-java" "datadog-apm-library-js" "datadog-apm-library-python" "datadog-apm-library-dotnet" "datadog-apm-library-ruby") # php is not installed by default yet
888fi
889
890no_config_change=
891if [ -n "$DD_APM_INSTRUMENTATION_NO_CONFIG_CHANGE" ]; then
892  no_config_change="--no-config-change"
893fi
894
895##
896# SETUP & VALIDATE CONFIGURATION
897##
898
899nice_flavor=$(getMapData flavor_to_readable "$agent_flavor")
900
901if [ -z "$nice_flavor" ]; then
902    ERROR_MESSAGE="Unknown DD_AGENT_FLAVOR \"$agent_flavor\""
903    ERROR_CODE=$INVALID_PARAMETERS_CODE
904    echo -e "\033[33m$ERROR_MESSAGE\033[0m"
905    fallback_msg
906    report_telemetry
907    exit 1;
908fi
909
910if [ "$agent_flavor" = "datadog-dogstatsd" ]; then
911    system_service="datadog-dogstatsd"
912    etcdir="/etc/datadog-dogstatsd"
913    config_file="$etcdir/dogstatsd.yaml"
914fi
915
916if [ -z "$system_service" ]; then
917    system_service="datadog-agent"
918fi
919
920declare -a services
921declare -a running_services
922
923if [ -n "$no_agent" ]; then
924  services=()
925else
926  services=("$system_service")
927fi
928
929if [ -n "$fips_mode" ]; then
930  services+=("datadog-fips-proxy")
931fi
932
933if [ -n "$remote_updates" ]; then
934  services+=("datadog-installer")
935fi
936
937# Track running services to avoid stopping them if they were already running
938if [[ $($sudo_cmd ps --no-headers -o comm 1 2>&1) == "systemd" ]] && command -v systemctl 2>&1; then
939  # Check with services are already running
940  for service in "${services[@]}"; do
941    if $sudo_cmd systemctl is-active --quiet "$service"; then
942      running_services+=("$service")
943    fi
944  done
945elif /sbin/init --version 2>&1 | grep -q upstart; then
946  # Check which services are already running
947  for service in "${services[@]}"; do
948    if $sudo_cmd status "$service" 2>&1 | grep -q "start/running"; then
949      running_services+=("$service")
950    fi
951  done
952fi
953
954if [ -z "$etcdir" ]; then
955    etcdir="/etc/datadog-agent"
956fi
957
958etcdirfips=/etc/datadog-fips-proxy
959
960if [ -z "$config_file" ]; then
961    config_file="$etcdir/datadog.yaml"
962fi
963
964config_file_fips=$etcdirfips/datadog-fips-proxy.cfg
965system_probe_config_file=$etcdir/system-probe.yaml
966security_agent_config_file=$etcdir/security-agent.yaml
967environment_file=/etc/environment
968dd_environment_file=/etc/datadog-agent/environment
969
970agent_major_version=7
971# shellcheck disable=SC2050
972# ^ to disable the warning about constant comparison in the elif clause below
973if [ -n "$DD_AGENT_MAJOR_VERSION" ]; then
974  if [ "$DD_AGENT_MAJOR_VERSION" != "6" ] && [ "$DD_AGENT_MAJOR_VERSION" != "7" ]; then
975    ERROR_MESSAGE="DD_AGENT_MAJOR_VERSION must be either 6 or 7. Current value: $DD_AGENT_MAJOR_VERSION"
976    ERROR_CODE=$INVALID_PARAMETERS_CODE
977    echo "$ERROR_MESSAGE"
978    report_telemetry
979    exit 1;
980  fi
981  agent_major_version=$DD_AGENT_MAJOR_VERSION
982elif [ "" == "true" ]; then
983  if [ "$agent_flavor" == "datadog-agent" ] ; then
984    echo -e "\033[33mWarning: DD_AGENT_MAJOR_VERSION not set. Installing $nice_flavor version 6 by default.\033[0m"
985  else
986    echo -e "\033[33mWarning: DD_AGENT_MAJOR_VERSION not set. Installing $nice_flavor version 7 by default.\033[0m"
987    agent_major_version=7
988  fi
989fi
990
991if [ -n "$DD_AGENT_MINOR_VERSION" ]; then
992  # Examples:
993  #  - 20   = defaults to highest patch version x.20.2
994  #  - 20.0 = sets explicit patch version x.20.0
995  # Note: Specifying an invalid minor version will terminate the script.
996  agent_minor_version=${DD_AGENT_MINOR_VERSION}
997  # Handle pre-release versions like "35.0~rc.5" -> "35.0" or "27.1~viper~conflict~fix" -> "27.1"
998  # Allow to get a "clean" version number that can be used to compare the version with others (e.g: "35.0~rc.5" < "36.0" because "35.0" < "36.0")
999  clean_agent_minor_version=$(echo "${DD_AGENT_MINOR_VERSION}" | sed -E 's/~.*//g')
1000  # remove the patch version if the minor version includes it (eg: 33.1 -> 33)
1001  agent_minor_version_without_patch="${clean_agent_minor_version%.*}"
1002fi
1003
1004agent_dist_channel=stable
1005if [ -n "$DD_AGENT_DIST_CHANNEL" ]; then
1006  if [ "$repository_url" == "datadoghq.com" ]; then
1007    if [ "$DD_AGENT_DIST_CHANNEL" != "stable" ] && [ "$DD_AGENT_DIST_CHANNEL" != "beta" ]; then
1008      ERROR_MESSAGE="DD_AGENT_DIST_CHANNEL must be either 'stable' or 'beta'. Current value: $DD_AGENT_DIST_CHANNEL"
1009      ERROR_CODE=$INVALID_PARAMETERS_CODE
1010      echo "$ERROR_MESSAGE"
1011      report_telemetry
1012      exit 1;
1013    fi
1014  elif [ "$DD_AGENT_DIST_CHANNEL" != "stable" ] && [ "$DD_AGENT_DIST_CHANNEL" != "beta" ] && [ "$DD_AGENT_DIST_CHANNEL" != "nightly" ]; then
1015    ERROR_MESSAGE="DD_AGENT_DIST_CHANNEL must be either 'stable', 'beta' or 'nightly' on custom repos. Current value: $DD_AGENT_DIST_CHANNEL"
1016    ERROR_CODE=$INVALID_PARAMETERS_CODE
1017    echo "$ERROR_MESSAGE"
1018    report_telemetry
1019    exit 1;
1020  fi
1021  agent_dist_channel=$DD_AGENT_DIST_CHANNEL
1022fi
1023
1024if [ -n "$TESTING_YUM_VERSION_PATH" ]; then
1025  yum_version_path=$TESTING_YUM_VERSION_PATH
1026else
1027  yum_version_path="${agent_dist_channel}/${agent_major_version}"
1028fi
1029
1030if [ -n "$TESTING_APT_REPO_VERSION" ]; then
1031  apt_repo_version=$TESTING_APT_REPO_VERSION
1032else
1033  apt_repo_version="${agent_dist_channel} ${agent_major_version}"
1034fi
1035
1036if [ ! "$apikey" ]; then
1037  # if it's an upgrade, then we will use the transition script
1038  if [ ! "$upgrade" ] && [ ! -e "$config_file" ] && [ ! "$no_agent" ]; then
1039    printf "\033[31mAPI key not available in DD_API_KEY environment variable.\033[0m\n"
1040    exit 1;
1041  fi
1042fi
1043
1044if [[ $(uname -m) == "armv7l" ]] && [[ $agent_flavor == "datadog-agent" ]] && [ ! "$no_agent" ]; then
1045    ERROR_MESSAGE="The full $nice_flavor isn't available for your architecture (armv7l).\nInstall the $(getMapData flavor_to_readable datadog-iot-agent) by setting DD_AGENT_FLAVOR='datadog-iot-agent'."
1046    ERROR_CODE=$UNSUPPORTED_PLATFORM_CODE
1047    printf "\033[31m$ERROR_MESSAGE\033[0m\n"
1048    report_telemetry
1049    exit 1;
1050fi
1051
1052if [ ${#apm_libraries[@]} -gt 0 ] && [ "$agent_major_version" = "6" ] ; then
1053  ERROR_MESSAGE="APM library injection is not supported with Agent version 6"
1054  ERROR_CODE=$INVALID_PARAMETERS_CODE
1055  echo -e "\033[31m$ERROR_MESSAGE\033[0m\n"
1056  report_telemetry
1057  exit 1;
1058fi
1059
1060# OS/Distro Detection
1061# Try lsb_release, fallback with /etc/issue then uname command
1062KNOWN_DISTRIBUTION="(Debian|Ubuntu|Red Hat|CentOS|openSUSE|Amazon|Arista|SUSE|Rocky|AlmaLinux)"
1063DISTRIBUTION=$(lsb_release -d 2>/dev/null | grep -Eo "$KNOWN_DISTRIBUTION" || grep -Eo "$KNOWN_DISTRIBUTION" /etc/issue 2>/dev/null || grep -Eo "$KNOWN_DISTRIBUTION" /etc/Eos-release 2>/dev/null || grep -m1 -Eo "$KNOWN_DISTRIBUTION" /etc/os-release 2>/dev/null || uname -s)
1064
1065if [ "$DISTRIBUTION" == "Darwin" ]; then
1066    ERROR_MESSAGE="This script does not support installing on the Mac."
1067    ERROR_CODE=$UNSUPPORTED_PLATFORM_CODE
1068    printf "\033[31m$ERROR_MESSAGE
1069
1070Please use the 1-step script available at https://app.datadoghq.com/account/settings/agent/latest?platform=macos.\033[0m\n"
1071    report_telemetry
1072    exit 1;
1073
1074elif [ -f /etc/debian_version ] || [ "$DISTRIBUTION" == "Debian" ] || [ "$DISTRIBUTION" == "Ubuntu" ]; then
1075    OS="Debian"
1076elif [ -f /etc/redhat-release ] || [ "$DISTRIBUTION" == "Red Hat" ] || [ "$DISTRIBUTION" == "CentOS" ] || [ "$DISTRIBUTION" == "Amazon" ] || [ "$DISTRIBUTION" == "Rocky" ] || [ "$DISTRIBUTION" == "AlmaLinux" ]; then
1077    OS="Red Hat"
1078# Some newer distros like Amazon may not have a redhat-release file
1079elif [ -f /etc/system-release ] || [ "$DISTRIBUTION" == "Amazon" ]; then
1080    OS="Red Hat"
1081# Arista is based off of Fedora14/18 but do not have /etc/redhat-release
1082elif [ -f /etc/Eos-release ] || [ "$DISTRIBUTION" == "Arista" ]; then
1083    OS="Red Hat"
1084# openSUSE and SUSE use /etc/SuSE-release or /etc/os-release
1085elif [ -f /etc/SuSE-release ] || [ "$DISTRIBUTION" == "SUSE" ] || [ "$DISTRIBUTION" == "openSUSE" ]; then
1086    OS="SUSE"
1087fi
1088
1089if [[ "$agent_flavor" == "datadog-dogstatsd" ]]; then
1090    if [[ $(uname -m) == "armv7l" ]] || { [[ $(uname -m) != "x86_64" ]] && [[ "$OS" != "Debian" ]]; }; then
1091        ERROR_MESSAGE="The $nice_flavor isn't available for your architecture."
1092        ERROR_CODE=$UNSUPPORTED_PLATFORM_CODE
1093        printf "\033[31m$ERROR_MESSAGE\033[0m\n"
1094        report_telemetry
1095        exit 1;
1096    fi
1097    if  [[ "$OS" == "Debian" ]] && [[ $(uname -m) == "aarch64" ]] && { [[ -n "$agent_minor_version_without_patch" ]] && [[ "$agent_minor_version_without_patch" -lt 35 ]]; }; then
1098        ERROR_MESSAGE="The $nice_flavor is only available since version 7.35.0 for your architecture."
1099        ERROR_CODE=$UNSUPPORTED_PLATFORM_CODE
1100        printf "\033[31m$ERROR_MESSAGE\033[0m\n"
1101        report_telemetry
1102        exit 1;
1103    fi
1104fi
1105
1106if [ -n "$fips_mode" ]; then
1107    UNAME_M=$(uname -m)
1108    if [[ ${UNAME_M} != "x86_64" ]] && [[ ${UNAME_M} != "aarch64" ]]; then
1109        ERROR_MESSAGE="FIPS mode isn't available for your architecture"
1110        ERROR_CODE=$UNSUPPORTED_PLATFORM_CODE
1111        printf "\033[31m$ERROR_MESSAGE\033[0m\n"
1112        report_telemetry
1113        exit 1;
1114    fi
1115    if [[ -n "$agent_minor_version_without_patch" ]] && [[ "${agent_minor_version_without_patch}" -lt 41 ]]; then
1116        ERROR_MESSAGE="FIPS mode is only available since version 7.41.0 and requested minor version is $agent_minor_version"
1117        ERROR_CODE=$INVALID_PARAMETERS_CODE
1118        printf "\033[31m$ERROR_MESSAGE\033[0m\n"
1119        report_telemetry
1120        exit 1;
1121    fi
1122fi
1123
1124# Root user detection
1125if [ "$UID" == "0" ]; then
1126    sudo_cmd=''
1127else
1128    sudo_cmd='sudo'
1129fi
1130
1131##
1132# INSTALL THE NECESSARY PACKAGE SOURCES
1133##
1134if [ "$OS" == "Red Hat" ]; then
1135    remove_rpm_gpg_keys "$sudo_cmd" "${RPM_GPG_KEYS_TO_REMOVE[@]}"
1136    if { [ "$DISTRIBUTION" == "Rocky" ] || [ "$DISTRIBUTION" == "AlmaLinux" ]; } && { [ -n "$agent_minor_version_without_patch" ] && [ "$agent_minor_version_without_patch" -lt 33 ]; } && ! echo "$agent_flavor" | grep '[0-9]' > /dev/null; then
1137        ERROR_MESSAGE="A future version of $nice_flavor will support $DISTRIBUTION"
1138        ERROR_CODE=$UNSUPPORTED_PLATFORM_CODE
1139        echo -e "\033[33m$ERROR_MESSAGE\n\033[0m"
1140        report_telemetry
1141        exit;
1142    fi
1143    # NOTE: CentOS/RHEL 6 don't have /etc/os-release. /etc/centos-release and /etc/redhat-release
1144    # aren't necessarily on the system, so this is not 100 % reliable, but best we can do
1145    release_version=$(cat /etc/redhat-release 2>/dev/null | grep -oE '[0-9]+' | head -1)
1146    if [ -z "$release_version" ]; then
1147        release_version=7
1148    fi
1149    if { [ "$DISTRIBUTION" == "Red Hat" ] || [ "$DISTRIBUTION" == "CentOS" ]; } && [ "$release_version" -lt 7 ]; then
1150        if [ -n "$agent_minor_version_without_patch" ]; then
1151            if [ "$agent_minor_version_without_patch" -ge "52" ]; then
1152                ERROR_MESSAGE="$DISTRIBUTION < 7 only supports $nice_flavor $agent_major_version up to $agent_major_version.51."
1153                ERROR_CODE=$UNSUPPORTED_PLATFORM_CODE
1154                printf "\033[31m$ERROR_MESSAGE\033[0m\n"
1155                report_telemetry
1156                exit;
1157            fi
1158        else
1159            if ! echo "$agent_flavor" | grep '[0-9]' > /dev/null; then
1160                echo -e "  \033[33m$nice_flavor $agent_major_version.51 is the last supported version on $DISTRIBUTION $release_version. Installing $agent_major_version.51 now.\n\033[0m"
1161                agent_minor_version=51
1162                clean_agent_minor_version=51
1163            fi
1164        fi
1165    fi
1166    echo -e "\033[34m\n* Installing YUM sources for Datadog\n\033[0m"
1167
1168    UNAME_M=$(uname -m)
1169    if [ "$UNAME_M" == "i686" ] || [ "$UNAME_M" == "i386" ] || [ "$UNAME_M" == "x86" ]; then
1170        ARCHI="i386"
1171    elif [ "$UNAME_M" == "aarch64" ]; then
1172        ARCHI="aarch64"
1173    else
1174        ARCHI="x86_64"
1175    fi
1176
1177    # Because of https://bugzilla.redhat.com/show_bug.cgi?id=1792506, we disable
1178    # repo_gpgcheck on RHEL/CentOS 8.1
1179    if [ -z "$rpm_repo_gpgcheck" ]; then
1180        if grep -q "8\.1\(\b\|\.\)" /etc/redhat-release 2>/dev/null; then
1181            rpm_repo_gpgcheck=0
1182        else
1183            rpm_repo_gpgcheck=1
1184        fi
1185    fi
1186
1187    gpgkeys=''
1188    separator='\n       '
1189    for key_path in "${RPM_GPG_KEYS[@]}"; do
1190      gpgkeys="${gpgkeys:+"${gpgkeys}${separator}"}https://${keys_url}/${key_path}"
1191    done
1192
1193    # if some packages were previously pinned (using excludepkgs)
1194    # this will unpin them as a side effect
1195    $sudo_cmd sh -c "echo -e '[datadog]\nname = Datadog, Inc.\nbaseurl = https://${yum_url}/${yum_version_path}/${ARCHI}/\nenabled=1\ngpgcheck=1\nrepo_gpgcheck=${rpm_repo_gpgcheck}\npriority=1\ngpgkey=${gpgkeys}' > /etc/yum.repos.d/datadog.repo"
1196
1197    $sudo_cmd yum -y clean metadata
1198
1199    dnf_flag=""
1200    if [ -f "/usr/bin/dnf" ] && { [ ! -f "/usr/bin/yum" ] || [ -L "/usr/bin/yum" ]; } ; then
1201      # On modern Red Hat based distros, yum is an alias (symlink) of dnf.
1202      # "dnf install" doesn't upgrade a package if a newer version
1203      # is available, unless the --best flag is set
1204      # NOTE: we assume that sometime in the future "/usr/bin/yum" will
1205      # be removed altogether, so we test for that as well.
1206      dnf_flag="--best"
1207    fi
1208
1209    if [ -n "$agent_minor_version" ]; then
1210        # Example: datadog-agent-7.20.2-1
1211        pkg_pattern="$agent_major_version\.${agent_minor_version%.}(\.[[:digit:]]+){0,1}(-[[:digit:]])?"
1212        agent_version_custom="$($sudo_cmd yum -y --disablerepo=* --enablerepo=datadog list --showduplicates datadog-agent | sort -r | grep -E "$pkg_pattern" -om1)" || true
1213        verify_agent_version "-"
1214    fi
1215
1216    declare -a packages
1217    if [ -n "$no_agent" ]; then
1218      packages=()
1219    else
1220      packages=("$agent_flavor")
1221    fi
1222
1223    if [ -n "$fips_mode" ]; then
1224      packages+=("datadog-fips-proxy")
1225    fi
1226
1227    excludepkgs=""
1228    if [ ${#apm_libraries[@]} -gt 0 ]; then
1229      for lib in "${apm_libraries[@]}"
1230      do
1231        cur_lib=$(echo "$lib" | cut -s -d':' -f1)
1232        cur_version=$(echo "$lib" | cut -s -d':' -f2)
1233        if [ -z "$cur_lib" ] ; then
1234          packages+=("${lib}")
1235        else
1236          packages+=("${cur_lib}-${cur_version}")
1237          excludepkgs="${excludepkgs:+${excludepkgs}, }${cur_lib}"
1238        fi
1239      done
1240    fi
1241
1242    # Install the installer
1243    # Note: this function will remove installed packages from the "packages" array
1244    install_installer "$sudo_cmd" "$OS" "$DISTRIBUTION" "$DD_INSTALLER" "$DD_REMOTE_UPDATES" "$DD_APM_INSTRUMENTATION_ENABLED" "packages" || true
1245
1246    # packages can be empty if no_agent is set
1247    if [ ${#packages[@]} -ne 0 ]; then
1248      echo -e "  \033[33mInstalling package(s): ${packages[*]}\n\033[0m"
1249
1250      # yum has a default retry of 10 https://github.com/Distrotech/yum/blob/f4e54aeed297158c563828aa3ebb93d0c8ce7e38/docs/yum.conf.5#L364-L366
1251      $sudo_cmd bash -c "SYSTEMD_OFFLINE=${SYSTEMD_OFFLINE:-0} yum -y --disablerepo='*' --enablerepo='datadog' install $dnf_flag ${packages[*]}" 2> >($sudo_cmd tee /tmp/ddog_install_error_msg >&2) || $sudo_cmd bash -c "SYSTEMD_OFFLINE=${SYSTEMD_OFFLINE:-0} yum -y install $dnf_flag ${packages[*]}" 2> >($sudo_cmd tee /tmp/ddog_install_error_msg >&2)
1252
1253      ERR_SUMMARY=$(grep "Error Summary" -A3 /tmp/ddog_install_error_msg || true)
1254    else
1255      echo -e "  \033[33mNo packages to install.\033[0m\n"
1256    fi
1257
1258    if [ -n "$excludepkgs" ]; then
1259        # exclude pinned tracer versions from updates
1260        repofile_content=$(cat /etc/yum.repos.d/datadog.repo)
1261        $sudo_cmd sh -c "echo -e '${repofile_content}\nexclude=${excludepkgs}' > /etc/yum.repos.d/datadog.repo"
1262    fi
1263
1264elif [ "$OS" == "Debian" ]; then
1265    apt_trusted_d_keyring="/etc/apt/trusted.gpg.d/datadog-archive-keyring.gpg"
1266    apt_usr_share_keyring="/usr/share/keyrings/datadog-archive-keyring.gpg"
1267
1268    DD_APT_INSTALL_ERROR_MSG=/tmp/ddog_install_error_msg
1269    MAX_RETRY_NB=10
1270    APT_DEPS=(curl gnupg)
1271    apt_version=$(apt-get --version | head -n 1 | cut -d ' ' -f 2)
1272    # apt-transport-https is only a transitive package for apt version >= 1.5.0
1273    # where https support was baked in
1274    # Sort will return an error code if the 2 compared versions are the same, so we
1275    # compare to 1.4.9
1276    set -o pipefail
1277    if printf "${apt_version}\n1.4.9" | sort -V -C; then
1278        echo "APT version (${apt_version} doesn't include HTTPS support, installing apt-transport-https"
1279        APT_DEPS+=("apt-transport-https")
1280    fi
1281    set +o pipefail
1282    for i in $(seq 1 $MAX_RETRY_NB)
1283    do
1284        printf "\033[34m\n* Installing ${APT_DEPS[*]}\n\033[0m\n"
1285        $sudo_cmd apt-get update || printf "\033[31m'apt-get update' failed, the script will not install the latest version of apt-transport-https.\033[0m\n"
1286        # installing curl might trigger install of additional version of libssl; this will fail the installation process,
1287        # see https://unix.stackexchange.com/q/146283 for reference - we use DEBIAN_FRONTEND=noninteractive to fix that
1288        apt_exit_code=0
1289        if [ -z "$sudo_cmd" ]; then
1290            # if $sudo_cmd is empty, doing `$sudo_cmd X=Y command` fails with
1291            # `X=Y: command not found`; therefore we don't prefix the command with
1292            # $sudo_cmd at all in this case
1293            DEBIAN_FRONTEND=noninteractive apt-get install -o Acquire::Retries="5" -y "${APT_DEPS[@]}" 2>$DD_APT_INSTALL_ERROR_MSG  || apt_exit_code=$?
1294        else
1295            $sudo_cmd DEBIAN_FRONTEND=noninteractive apt-get install -o Acquire::Retries="5" -y "${APT_DEPS[@]}" 2> >($sudo_cmd tee $DD_APT_INSTALL_ERROR_MSG >&2) || apt_exit_code=$?
1296        fi
1297
1298        if grep "Could not get lock" $DD_APT_INSTALL_ERROR_MSG; then
1299            RETRY_TIME=$((i*5))
1300            printf "\033[31mInstallation failed: Unable to get lock.\nRetrying in ${RETRY_TIME}s ($i/$MAX_RETRY_NB).\033[0m\n"
1301            sleep $RETRY_TIME
1302        elif [ $apt_exit_code -ne 0 ]; then
1303            cat $DD_APT_INSTALL_ERROR_MSG
1304            exit $apt_exit_code
1305        else
1306            break
1307        fi
1308    done
1309
1310    printf "\033[34m\n* Installing APT package sources for Datadog\n\033[0m\n"
1311    $sudo_cmd sh -c "echo 'deb [signed-by=${apt_usr_share_keyring}] https://${apt_url}/ ${apt_repo_version}' > /etc/apt/sources.list.d/datadog.list"
1312    $sudo_cmd sh -c "chmod a+r /etc/apt/sources.list.d/datadog.list"
1313
1314    if [ ! -f $apt_usr_share_keyring ]; then
1315        $sudo_cmd touch $apt_usr_share_keyring
1316    fi
1317    # ensure that the _apt user used on Ubuntu/Debian systems to read GPG keyrings
1318    # can read our keyring
1319    $sudo_cmd chmod a+r $apt_usr_share_keyring
1320
1321    for key in "${APT_GPG_KEYS[@]}"; do
1322        $sudo_cmd curl -sSL --retry 5 -o "/tmp/${key}" "https://${keys_url}/${key}"
1323        $sudo_cmd cat "/tmp/${key}" | $sudo_cmd gpg --import --batch --no-default-keyring --keyring "$apt_usr_share_keyring"
1324    done
1325
1326    release_version="$(grep VERSION_ID /etc/os-release | cut -d = -f 2 | xargs echo | cut -d "." -f 1)"
1327    if { [ "$DISTRIBUTION" == "Debian" ] && [ "$release_version" -lt 9 ]; } || \
1328       { [ "$DISTRIBUTION" == "Ubuntu" ] && [ "$release_version" -lt 16 ]; }; then
1329        # copy with -a to preserve file permissions
1330        $sudo_cmd cp -a $apt_usr_share_keyring $apt_trusted_d_keyring
1331    fi
1332
1333    if [ "$DISTRIBUTION" == "Debian" ] && [ "$release_version" -lt 8 ]; then
1334      if [ -n "$agent_minor_version_without_patch" ]; then
1335          if [ "$agent_minor_version_without_patch" -ge "36" ]; then
1336              ERROR_MESSAGE="Debian < 8 only supports $nice_flavor $agent_major_version up to $agent_major_version.35."
1337              ERROR_CODE=$UNSUPPORTED_PLATFORM_CODE
1338              printf "\033[31m$ERROR_MESSAGE\033[0m\n"
1339              report_telemetry
1340              exit;
1341          fi
1342      else
1343          if ! echo "$agent_flavor" | grep '[0-9]' > /dev/null; then
1344              echo -e "  \033[33m$nice_flavor $agent_major_version.35 is the last supported version on $DISTRIBUTION $release_version. Installing $agent_major_version.35 now.\n\033[0m"
1345              agent_minor_version=35
1346              clean_agent_minor_version=35
1347          fi
1348      fi
1349    fi
1350
1351    ERROR_MESSAGE="ERROR
1352Failed to update the sources after adding the Datadog repository.
1353This may be due to any of the configured APT sources failing -
1354see the logs above to determine the cause.
1355If the failing repository is Datadog, please contact Datadog support.
1356*****
1357"
1358    $sudo_cmd apt-get update -o Dir::Etc::sourcelist="sources.list.d/datadog.list" -o Dir::Etc::sourceparts="-" -o APT::Get::List-Cleanup="0"
1359    ERROR_MESSAGE="ERROR
1360Failed to install one or more packages, sometimes it may be
1361due to another APT source failing. See the logs above to
1362determine the cause.
1363If the cause is unclear, please contact Datadog support.
1364*****
1365"
1366
1367    if [ -n "$agent_minor_version" ]; then
1368        # Example: datadog-agent=1:7.20.2-1
1369        pkg_pattern="([[:digit:]]:)?$agent_major_version\.${agent_minor_version%.}(\.[[:digit:]]+){0,1}(-[[:digit:]])?"
1370        agent_version_custom="$(apt-cache madison datadog-agent | grep -E "$pkg_pattern" -om1)" || true
1371        verify_agent_version "="
1372    fi
1373
1374    declare -a packages
1375    if [ -n "$no_agent" ]; then
1376      packages=("datadog-signing-keys")
1377    else
1378      packages=("$agent_flavor" "datadog-signing-keys")
1379    fi
1380
1381    if [ -n "$fips_mode" ]; then
1382     packages+=("datadog-fips-proxy")
1383    fi
1384
1385    packages_to_lock=()
1386    if [ ${#apm_libraries[@]} -gt 0 ]; then
1387      for lib in "${apm_libraries[@]}"
1388      do
1389        cur_lib=$(echo "$lib" | cut -s -d':' -f1)
1390        cur_version=$(echo "$lib" | cut -s -d':' -f2)
1391        if [ -z "$cur_lib" ] ; then
1392          packages+=("${lib}")
1393          # the tracer might have been excluded from updates previously => un-hold it
1394          $sudo_cmd dpkg --set-selections <<< "${lib} install" >/dev/null 2>&1
1395        else
1396          packages_to_lock+=("${cur_lib}")
1397          packages+=("${cur_lib}=${cur_version}")
1398          $sudo_cmd dpkg --set-selections <<< "${cur_lib} install" >/dev/null 2>&1
1399        fi
1400      done
1401    fi
1402
1403    # Install the installer
1404    # Note: this function will remove installed packages from the "packages" array
1405    install_installer "$sudo_cmd" "$OS" "$DISTRIBUTION" "$DD_INSTALLER" "$DD_REMOTE_UPDATES" "$DD_APM_INSTRUMENTATION_ENABLED" "packages" || true
1406
1407    echo -e "  \033[33mInstalling package(s): ${packages[*]}\n\033[0m"
1408
1409    # apt-get will automatically start the service after installation
1410    # As a workaround, we can use policy.d to prevent this behavior
1411    POLICYRCD=/tmp/policy-do-not-start-service-rc.d
1412    echo exit 101 > "${POLICYRCD}"
1413    $sudo_cmd chmod +x "${POLICYRCD}"
1414
1415    $sudo_cmd bash -c "POLICYRCD='${POLICYRCD}' apt-get install -o Acquire::Retries='5' -y --force-yes ${packages[*]} 2> >($sudo_cmd tee /tmp/ddog_install_error_msg >&2)"
1416
1417    for pkg in "${packages_to_lock[@]}"
1418    do
1419        if $sudo_cmd dpkg -l "${pkg}" >/dev/null 2>&1 ; then
1420          # exclude pinned tracer versions from updates if they're installed through debs
1421          $sudo_cmd apt-mark hold "${pkg}" >/dev/null 2>&1
1422        fi
1423    done
1424
1425    ERR_SUMMARY=$(grep "No space left on device" -C1 /tmp/ddog_install_error_msg || true)
1426
1427    ERROR_MESSAGE=""
1428elif [ "$OS" == "SUSE" ]; then
1429  remove_rpm_gpg_keys "$sudo_cmd" "${RPM_GPG_KEYS_TO_REMOVE[@]}"
1430  UNAME_M=$(uname -m)
1431  if [ "$UNAME_M"  == "i686" ] || [ "$UNAME_M"  == "i386" ] || [ "$UNAME_M"  == "x86" ]; then
1432      ERROR_MESSAGE="The Datadog Agent installer is only available for 64 bit SUSE Enterprise machines."
1433      ERROR_CODE=$UNSUPPORTED_PLATFORM_CODE
1434      printf "\033[31m$ERROR_MESSAGE\033[0m\n"
1435      report_telemetry
1436      exit;
1437  elif [ "$UNAME_M"  == "aarch64" ]; then
1438      ARCHI="aarch64"
1439  else
1440      ARCHI="x86_64"
1441  fi
1442
1443  if [ -z "$rpm_repo_gpgcheck" ]; then
1444      rpm_repo_gpgcheck=1
1445  fi
1446
1447  # Try to guess if we're installing on SUSE 11, as it needs a different flow to work
1448  # Note that SUSE11 doesn't have /etc/os-release file, so we have to use /etc/SuSE-release
1449  if cat /etc/SuSE-release 2>/dev/null | grep VERSION | grep 11; then
1450    SUSE11="yes"
1451  fi
1452
1453  # Doing "rpm --import" requires curl on SUSE/SLES
1454  echo -e "\033[34m\n* Ensuring curl is installed\n\033[0m\n"
1455  if ! rpm -q curl > /dev/null; then
1456    # If zypper fails to refresh a random repo, it installs the package, but then fails
1457    # anyway. Therefore we let it do its thing and then see if curl was installed or not.
1458    # Not yet retry mechanism in zypper, see https://github.com/openSUSE/zypper/issues/420
1459    if [ -z "$sudo_cmd" ]; then
1460      ZYPP_RPM_DEBUG="${ZYPP_RPM_DEBUG:-0}" zypper --non-interactive install curl ||:
1461    else
1462      $sudo_cmd ZYPP_RPM_DEBUG="${ZYPP_RPM_DEBUG:-0}" zypper --non-interactive install curl ||:
1463    fi
1464    if ! rpm -q curl > /dev/null; then
1465      ERROR_MESSAGE="Failed to install curl."
1466      ERROR_CODE=$UNABLE_TO_INSTALL_DEPENDENCY_CODE
1467      echo -e "\033[31m$ERROR_MESSAGE\033[0m\n"
1468      fallback_msg
1469      report_telemetry
1470      exit 1;
1471    fi
1472  fi
1473
1474  echo -e "\033[34m\n* Importing the Datadog GPG Keys\n\033[0m"
1475  if [ "$SUSE11" == "yes" ]; then
1476    # SUSE 11 special case
1477    for key_path in "${RPM_GPG_KEYS[@]}"; do
1478      $sudo_cmd curl -sSL --retry 5 -o "/tmp/${key_path}" "https://${keys_url}/${key_path}"
1479      $sudo_cmd rpm --import "/tmp/${key_path}"
1480    done
1481  else
1482    for key_path in "${RPM_GPG_KEYS[@]}"; do
1483      $sudo_cmd rpm --import "https://${keys_url}/${key_path}"
1484    done
1485  fi
1486
1487  # Parse the major version number out of the distro release info file. xargs is used to trim whitespace.
1488  # NOTE: We use this to find out whether or not release version is >= 15, so we have to use /etc/os-release,
1489  # as /etc/SuSE-release has been deprecated and is no longer present everywhere, e.g. in AWS AMI.
1490  # See https://www.suse.com/releasenotes/x86_64/SUSE-SLES/15/#fate-324409
1491  SUSE_VER=$(cat /etc/os-release 2>/dev/null | grep VERSION_ID | tr -d '"' | tr . = | cut -d = -f 2 | xargs echo)
1492  gpgkeys="https://${keys_url}/DATADOG_RPM_KEY_CURRENT.public"
1493  if [ -n "$SUSE_VER" ] && [ "$SUSE_VER" -ge 15 ] && [ "$SUSE_VER" -ne 42 ]; then
1494    gpgkeys=''
1495    separator='\n       '
1496    for key_path in "${RPM_GPG_KEYS[@]}"; do
1497      gpgkeys="${gpgkeys:+"${gpgkeys}${separator}"}https://${keys_url}/${key_path}"
1498    done
1499  fi
1500
1501  echo -e "\033[34m\n* Installing YUM Repository for Datadog\n\033[0m"
1502  $sudo_cmd sh -c "echo -e '[datadog]\nname=datadog\nenabled=1\nbaseurl=https://${yum_url}/suse/${yum_version_path}/${ARCHI}\ntype=rpm-md\ngpgcheck=1\nrepo_gpgcheck=${rpm_repo_gpgcheck}\ngpgkey=${gpgkeys}' > /etc/zypp/repos.d/datadog.repo"
1503
1504  echo -e "\033[34m\n* Refreshing repositories\n\033[0m"
1505  $sudo_cmd zypper --non-interactive --no-gpg-checks refresh datadog
1506
1507  # ".32" is the latest version supported for OpenSUSE < 15 and SLES < 12
1508  # we explicitly test for SUSE11 = "yes", as some SUSE11 don't have /etc/os-release, thus SUSE_VER is empty
1509  if [ "$DISTRIBUTION" == "openSUSE" ] && { [ "$SUSE11" == "yes" ] || [ "$SUSE_VER" -lt 15 ]; }; then
1510      if [ -n "$agent_minor_version_without_patch" ]; then
1511          if [ "$agent_minor_version_without_patch" -ge "33" ]; then
1512              ERROR_MESSAGE="openSUSE < 15 only supports $nice_flavor $agent_major_version up to $agent_major_version.32."
1513              ERROR_CODE=$UNSUPPORTED_PLATFORM_CODE
1514              printf "\033[31m$ERROR_MESSAGE\033[0m\n"
1515              report_telemetry
1516              exit;
1517          fi
1518      else
1519          if ! echo "$agent_flavor" | grep '[0-9]' > /dev/null; then
1520              echo -e "  \033[33m$nice_flavor $agent_major_version.32 is the last supported version on $DISTRIBUTION $SUSE_VER\n\033[0m"
1521              agent_minor_version=32
1522              clean_agent_minor_version=32
1523          fi
1524      fi
1525  fi
1526  if [ "$DISTRIBUTION" == "SUSE" ] && { [ "$SUSE11" == "yes" ] || [ "$SUSE_VER" -lt 12 ]; }; then
1527      if [ -n "$agent_minor_version_without_patch" ]; then
1528          if [ "$agent_minor_version_without_patch" -ge "33" ]; then
1529              ERROR_MESSAGE="SLES < 12 only supports $nice_flavor $agent_major_version up to $agent_major_version.32."
1530              ERROR_CODE=$UNSUPPORTED_PLATFORM_CODE
1531              printf "\033[31m$ERROR_MESSAGE\033[0m\n"
1532              report_telemetry
1533              exit;
1534          fi
1535      else
1536          if ! echo "$agent_flavor" | grep '[0-9]' > /dev/null; then
1537              echo -e "  \033[33m$nice_flavor $agent_major_version.32 is the last supported version on $DISTRIBUTION $SUSE_VER\n\033[0m"
1538              agent_minor_version=32
1539              clean_agent_minor_version=32
1540          fi
1541      fi
1542  fi
1543
1544  if [ -n "$agent_minor_version" ]; then
1545      # Example: datadog-agent-1:7.20.2-1
1546      pkg_pattern="([[:digit:]]:)?$agent_major_version\.${agent_minor_version%.}(\.[[:digit:]]+){0,1}(-[[:digit:]])?"
1547      agent_version_custom="$(zypper search -s datadog-agent | grep -E "$pkg_pattern" -om1)" || true
1548      verify_agent_version "-"
1549  fi
1550
1551  declare -a packages
1552  if [ -n "$no_agent" ]; then
1553    packages=()
1554  else
1555    packages=("$agent_flavor")
1556  fi
1557  if [ -n "$fips_mode" ]; then
1558    packages+=("datadog-fips-proxy")
1559  fi
1560
1561  if [ ${#apm_libraries[@]} -gt 0 ]; then
1562    ERROR_MESSAGE="APM injection is not supported on SUSE"
1563    ERROR_CODE=$UNSUPPORTED_PLATFORM_CODE
1564    echo -e "\033[31m$ERROR_MESSAGE\033[0m\n"
1565    report_telemetry
1566    exit 1;
1567  fi
1568
1569    # Install the installer
1570    # Note: this function will remove installed packages from the "packages" array
1571    install_installer "$sudo_cmd" "$OS" "$DISTRIBUTION" "$DD_INSTALLER" "$DD_REMOTE_UPDATES" "$DD_APM_INSTRUMENTATION_ENABLED" "packages" || true
1572
1573  if [ ${#packages[@]} -ne 0 ]; then
1574    echo -e "  \033[33mInstalling package(s): ${packages[*]}\n\033[0m"
1575    # Not yet retry mechanism in zypper, see https://github.com/openSUSE/zypper/issues/420
1576    if [ -z "$sudo_cmd" ]; then
1577      ZYPP_RPM_DEBUG="${ZYPP_RPM_DEBUG:-0}" SYSTEMD_OFFLINE=${SYSTEMD_OFFLINE:-0} zypper --non-interactive --no-refresh install "${packages[@]}" 2> >($sudo_cmd tee /tmp/ddog_install_error_msg >&2) ||:
1578    else
1579      $sudo_cmd ZYPP_RPM_DEBUG="${ZYPP_RPM_DEBUG:-0}" SYSTEMD_OFFLINE="${SYSTEMD_OFFLINE:-0}" zypper --non-interactive --no-refresh install "${packages[@]}" 2> >($sudo_cmd tee /tmp/ddog_install_error_msg >&2) ||:
1580    fi
1581
1582    ERR_SUMMARY=$(grep "Write error" -C1 /tmp/ddog_install_error_msg || true)
1583  else
1584    echo -e "  \033[33mNo packages to install.\033[0m\n"
1585  fi
1586
1587  # Confirm the packages were installed
1588  for expected_pkg in "${packages[@]}"; do
1589    if ! rpm -q "${expected_pkg}" > /dev/null; then
1590      ERROR_MESSAGE="Failed to install ${expected_pkg}."
1591      ERROR_CODE=$UNABLE_TO_INSTALL_DEPENDENCY_CODE
1592      echo -e "\033[31m$ERROR_MESSAGE\033[0m\n"
1593      fallback_msg
1594      report_telemetry
1595      exit 1;
1596    fi
1597  done
1598
1599else
1600    ERROR_MESSAGE="Your OS or distribution are not supported by this install script.
1601Please follow the instructions on the Agent setup page:
1602
1603https://app.datadoghq.com/account/settings/agent/latest?platform=overview"
1604    ERROR_CODE=$UNSUPPORTED_PLATFORM_CODE
1605    printf "\033[31m$ERROR_MESSAGE\033[0m\n"
1606    report_telemetry
1607    exit;
1608fi
1609
1610##
1611# UPGRADE FROM AGENT 5
1612##
1613if [ -n "$upgrade" ] && [ "$agent_flavor" != "datadog-dogstatsd" ]; then
1614  if [ -e $LEGACY_CONF ]; then
1615    # try to import the config file from the previous version
1616    icmd="datadog-agent import $LEGACY_ETCDIR $etcdir"
1617    # shellcheck disable=SC2086
1618    $sudo_cmd $icmd || printf "\033[31mAutomatic import failed, you can still try to manually run: $icmd\n\033[0m\n"
1619    # fix file owner and permissions since the script moves around some files
1620    $sudo_cmd chown -R dd-agent:dd-agent "$etcdir"
1621    $sudo_cmd find "$etcdir/" -type f -exec chmod 640 {} \;
1622  else
1623    printf "\033[31mYou don't have a datadog.conf file to convert.\n\033[0m\n"
1624  fi
1625fi
1626
1627##
1628# SET THE CONFIGURATION
1629##
1630# Unit method
1631function update_api_key() {
1632  local sudo_cmd="$1"
1633  local apikey="$2"
1634  local config_file="$3"
1635  if [ -n "$apikey" ]; then
1636    printf "\033[34m\n* Adding your API key to the $nice_flavor configuration: $config_file\n\033[0m\n"
1637    $sudo_cmd sh -c "sed -i 's/api_key:.*/api_key: $apikey/' $config_file"
1638  else
1639    # If the import script failed for any reason, we might end here also in case
1640    # of upgrade, let's not start the agent or it would fail because the api key
1641    # is missing
1642    if ! $sudo_cmd grep -q -E '^api_key: .+' "$config_file"; then
1643      printf "\033[31mThe $nice_flavor won't start automatically at the end of the script because the Api key is missing, please add one in datadog.yaml and start the $nice_flavor manually.\n\033[0m\n"
1644      no_start=true
1645    fi
1646  fi
1647}
1648function update_site() {
1649  local sudo_cmd="$1"
1650  local site="$2"
1651  local config_file="$3"
1652  if [ -n "$site" ]; then
1653    printf "\033[34m\n* Setting SITE in the $nice_flavor configuration: $config_file\n\033[0m\n"
1654    $sudo_cmd sh -c "sed -i 's/^# site:.*$/site: $site/' $config_file"
1655  fi
1656}
1657function update_url() {
1658  local sudo_cmd="$1"
1659  local url="$2"
1660  local config_file="$3"
1661  if [ -n "$url" ]; then
1662    printf "\033[34m\n* Setting DD_URL in the $nice_flavor configuration: $config_file\n\033[0m\n"
1663    $sudo_cmd sh -c "sed -i 's|^# dd_url:.*$|dd_url: $url|' $config_file"
1664  fi
1665}
1666function update_fips() {
1667  local sudo_cmd="$1"
1668  local config_file="$2"
1669  printf "\033[34m\n* Setting $nice_flavor configuration to use FIPS proxy: $config_file\n\033[0m\n"
1670  $sudo_cmd cp "$config_file" "${config_file}.orig"
1671  $sudo_cmd sh -c "exec cat - '${config_file}.orig' > '$config_file'" <<EOF
1672# Configuration for the agent to use datadog-fips-proxy to communicate with Datadog via FIPS-compliant channel.
1673
1674fips:
1675    enabled: true
1676    port_range_start: 9803
1677    https: false
1678EOF
1679}
1680function update_hostname(){
1681  local sudo_cmd="$1"
1682  local hostname="$2"
1683  local config_file="$3"
1684  if [ -n "$hostname" ]; then
1685    printf "\033[34m\n* Adding your HOSTNAME to the $nice_flavor configuration: $config_file\n\033[0m\n"
1686    $sudo_cmd sh -c "sed -i 's/^# hostname:.*$/hostname: $hostname/' $config_file"
1687  fi
1688}
1689function update_hosttags(){
1690  local sudo_cmd="$1"
1691  local host_tags="$2"
1692  local config_file="$3"
1693  if [ -n "$host_tags" ]; then
1694      printf "\033[34m\n* Adding your HOST TAGS to the $nice_flavor configuration: $config_file\n\033[0m\n"
1695      formatted_host_tags="['""$( echo "$host_tags" | sed "s/,/', '/g" )""']"  # format `env:prod,foo:bar` to yaml-compliant `['env:prod','foo:bar']`
1696      $sudo_cmd sh -c "sed -i \"s/^# tags:.*$/tags: ""$formatted_host_tags""/\" $config_file"
1697  fi
1698}
1699function update_env(){
1700  local sudo_cmd="$1"
1701  local dd_env="$2"
1702  local config_file="$3"
1703  if [ -n "$dd_env" ]; then
1704    printf "\033[34m\n* Adding your DD_ENV to the $nice_flavor configuration: $config_file\n\033[0m\n"
1705    $sudo_cmd sh -c "sed -i 's/^# env:.*/env: $dd_env/' $config_file"
1706  fi
1707}
1708function update_fleet_automation(){
1709  local sudo_cmd="$1"
1710  local remote_updates="$2"
1711  local remote_policies="$3"
1712  local fips_mode="$4"
1713  local site="$5"
1714  local config_file="$6"
1715
1716  if [ -n "$fips_mode" ]; then
1717    printf "\033[31mFleet automation is not supported in FIPS mode.\033[0m\n"
1718    return 0
1719  elif [ "$site" == "ddog-gov.com" ]; then
1720    printf "\033[31mFleet automation is not supported with the Datadog Gov site.\033[0m\n"
1721    return 0
1722  fi
1723
1724  if [ -n "$remote_updates" ]; then
1725    printf "\033[34m\n* Adding your DD_REMOTE_UPDATES to the $nice_flavor configuration: $config_file\n\033[0m\n"
1726    if ! $sudo_cmd grep -q "^remote_updates:" "$config_file"; then
1727        $sudo_cmd sh -c "echo 'remote_updates: $remote_updates' >> $config_file"
1728    else
1729        $sudo_cmd sh -c "sed -i 's/^remote_updates:.*/remote_updates: $remote_updates/' $config_file"
1730    fi
1731  fi
1732  if [ -n "$remote_policies" ]; then
1733    printf "\033[34m\n* Adding your DD_REMOTE_POLICIES to the $nice_flavor configuration: $config_file\n\033[0m\n"
1734    if ! $sudo_cmd grep -q "^remote_policies:" "$config_file"; then
1735        $sudo_cmd sh -c "echo 'remote_policies: $remote_policies' >> $config_file"
1736    else
1737        $sudo_cmd sh -c "sed -i 's/^remote_policies:.*/remote_policies: $remote_policies/' $config_file"
1738    fi
1739  fi
1740}
1741function update_installer_registry(){
1742  local sudo_cmd="$1"
1743  local registry_url="$2"
1744  local registry_auth="$3"
1745  local config_file="$4"
1746  if [ -n "$registry_url" ] || [ -n "$registry_auth" ]; then
1747    printf "\033[34m\n* Adding your DD_INSTALLER_REGISTRY_URL and DD_INSTALLER_REGISTRY_AUTH to the $nice_flavor configuration: $config_file\n\033[0m\n"
1748    if ! $sudo_cmd grep -q "^installer:" "$config_file"; then
1749      $sudo_cmd sh -c "echo 'installer: {registry: {url: \"$registry_url\", auth: \"$registry_auth\" }}' >> $config_file"
1750    else
1751      printf "\033[31mInstaller configuration already exists in $config_file, skipping the update.\033[0m\n"
1752    fi
1753  fi
1754}
1755function update_security_and_or_compliance(){
1756  local sudo_cmd="$1"
1757  local local_config_file="$2"
1758  local enable_security="$3"
1759  local enable_compliance="$4"
1760  if [ "$enable_security" == "true" ]; then
1761    printf "\033[34m\n* Enabling runtime security in $local_config_file configuration\n\033[0m\n"
1762    $sudo_cmd sh -c "sed -i 's/^#\s*runtime_security_config:$/runtime_security_config:/' $local_config_file"
1763    $sudo_cmd sh -c "sed -i '/^runtime_security_config:/,// s/\(\s\+\)#\s*enabled:\s*false/\1enabled: true/' $local_config_file"
1764  fi
1765  if [ "$enable_compliance" == "true" ]; then
1766    printf "\033[34m\n* Enabling compliance monitoring in $local_config_file configuration\n\033[0m\n"
1767    $sudo_cmd sh -c "sed -i 's/^#\s*compliance_config:$/compliance_config:/' $local_config_file"
1768    $sudo_cmd sh -c "sed -i '/^compliance_config:/,// s/\(\s\+\)#\s*enabled:\s*false/\1enabled: true/' $local_config_file"
1769  fi
1770}
1771function manage_security_and_system_probe_config(){
1772  local sudo_cmd="$1"
1773  local security_config_file="$2"
1774  local probe_config_file="$3"
1775  local enable_security="$4"
1776  local enable_compliance="$5"
1777  if [ "$enable_security" == "true" ] || [ "$enable_compliance" == "true" ]; then
1778    if ensure_config_file_exists "$sudo_cmd" "$security_config_file" "root"; then
1779      update_security_and_or_compliance "$sudo_cmd" "$security_config_file" "$enable_security" "$enable_compliance"
1780    fi
1781    if [ "$enable_security" == "true" ]; then
1782      if ensure_config_file_exists "$sudo_cmd" "$probe_config_file" "root"; then
1783        update_security_and_or_compliance "$sudo_cmd" "$probe_config_file" "$enable_security" "false"
1784      fi
1785    fi
1786  fi
1787}
1788function set_in_env_file(){
1789  local sudo_cmd="$1"
1790  local etc_environment="$2"
1791  local key="$3"
1792  local value="$4"
1793  $sudo_cmd sed -i "/^$key=/d" "$etc_environment" > /dev/null
1794  echo "$key=$value" | $sudo_cmd tee -a "$etc_environment" > /dev/null
1795}
1796function manage_infrastructure_vulnerabilities_config(){
1797  local sudo_cmd="$1"
1798  local etc_environment="$2"
1799  local container_image_vm_enable="$3"
1800  local host_vm_enable="$4"
1801  $sudo_cmd touch "$etc_environment"
1802  if [ "$container_image_vm_enable" == "true" ] || [ "$host_vm_enable" == "true" ]; then
1803    set_in_env_file "$sudo_cmd" "$etc_environment" DD_SBOM_ENABLED true
1804  fi
1805  if [ -n "$container_image_vm_enable" ]; then
1806    set_in_env_file "$sudo_cmd" "$etc_environment" DD_SBOM_CONTAINER_IMAGE_ENABLED "$container_image_vm_enable"
1807  fi
1808  if [ -n "$host_vm_enable" ]; then
1809    set_in_env_file "$sudo_cmd" "$etc_environment" DD_SBOM_HOST_ENABLED "$host_vm_enable"
1810  fi
1811}
1812function manage_client_libraries_security_config(){
1813  local sudo_cmd="$1"
1814  local etc_environment="$2"
1815  local asm_enable="$3"
1816  local iast_enable="$4"
1817  local sca_enable="$5"
1818  $sudo_cmd touch "$etc_environment"
1819  if [ -n "$asm_enable" ]; then
1820    set_in_env_file "$sudo_cmd" "$etc_environment" DD_APPSEC_ENABLED "$asm_enable"
1821  fi
1822  if [ -n "$iast_enable" ]; then
1823    set_in_env_file "$sudo_cmd" "$etc_environment" DD_IAST_ENABLED "$iast_enable"
1824  fi
1825  if [ -n "$sca_enable" ]; then
1826    set_in_env_file "$sudo_cmd" "$etc_environment" DD_APPSEC_SCA_ENABLED "$sca_enable"
1827  fi
1828}
1829function manage_client_libraries_profiling_config(){
1830  local sudo_cmd="$1"
1831  local etc_environment="$2"
1832  local profiling_enable="$3"
1833  if [ -n "$profiling_enable" ]; then
1834    if [ ! -s "$etc_environment" ]; then
1835      echo "DD_PROFILING_ENABLED=$profiling_enable" | $sudo_cmd tee "$etc_environment" > /dev/null
1836    else
1837      $sudo_cmd sed -i -n -e '/^DD_PROFILING_ENABLED=/!p' -e "\$aDD_PROFILING_ENABLED=$profiling_enable" "$etc_environment"
1838    fi
1839  fi
1840}
1841# "Main" configuration update
1842if [ -e "$config_file" ] && [ -z "$upgrade" ]; then
1843  printf "\033[34m\n* Keeping old $config_file configuration file\n\033[0m\n"
1844elif [ ! "$no_agent" ]; then
1845  if ensure_config_file_exists "$sudo_cmd" "$config_file" "dd-agent"; then
1846    update_api_key "$sudo_cmd" "$apikey" "$config_file"
1847    if [ -z "$fips_mode" ]; then
1848      update_site "$sudo_cmd" "$site" "$config_file"
1849      update_url "$sudo_cmd" "$DD_URL" "$config_file"
1850    else
1851      update_fips "$sudo_cmd" "$config_file"
1852    fi
1853    update_hostname "$sudo_cmd" "$hostname" "$config_file"
1854    update_hosttags "$sudo_cmd" "$host_tags" "$config_file"
1855    update_env "$sudo_cmd" "$dd_env" "$config_file"
1856  fi
1857  manage_security_and_system_probe_config "$sudo_cmd" "$security_agent_config_file" "$system_probe_config_file" "$DD_RUNTIME_SECURITY_CONFIG_ENABLED" "$DD_COMPLIANCE_CONFIG_ENABLED"
1858fi
1859
1860manage_client_libraries_security_config "$sudo_cmd" "$environment_file" "$DD_APPSEC_ENABLED" "$DD_IAST_ENABLED" "$DD_APPSEC_SCA_ENABLED"
1861manage_client_libraries_profiling_config "$sudo_cmd" "$environment_file" "$DD_PROFILING_ENABLED"
1862if [ -e "$(dirname $dd_environment_file)" ]; then
1863  manage_infrastructure_vulnerabilities_config "$sudo_cmd" "$dd_environment_file" "$DD_SBOM_CONTAINER_IMAGE_ENABLED" "$DD_SBOM_HOST_ENABLED"
1864fi
1865
1866update_fleet_automation "$sudo_cmd" "$remote_updates" "$remote_policies" "$fips_mode" "$site" "$config_file"
1867update_installer_registry "$sudo_cmd" "$installer_registry_url" "$installer_registry_auth" "$config_file"
1868
1869if [ ! "$no_agent" ]; then
1870  $sudo_cmd chown dd-agent:dd-agent "$config_file"
1871  $sudo_cmd chmod 640 "$config_file"
1872fi
1873
1874# set the FIPS configuration
1875if [ -n "$fips_mode" ]; then
1876  ensure_config_file_exists "$sudo_cmd" "$config_file_fips" "dd-agent"
1877  # TODO: set port range in file, or environment variable
1878fi
1879
1880# set the system-probe configuration
1881if [ -n "$system_probe_ensure_config" ]; then
1882  ensure_config_file_exists "$sudo_cmd" "$system_probe_config_file" "root"
1883fi
1884
1885# run apm injection scripts
1886if ! is_installed_by_installer "$sudo_cmd" "datadog-apm-inject"; then
1887  if [ -n "$host_injection_enabled" ]; then
1888    $sudo_cmd dd-host-install --no-agent-restart ${no_config_change}
1889  fi
1890
1891  if [ -n "$docker_injection_enabled" ]; then
1892    $sudo_cmd dd-container-install --no-agent-restart
1893  fi
1894fi
1895
1896# Creating or overriding the install information
1897function generate_install_id() {
1898  # Try generating a UUID based on /proc/sys/kernel/random/uuid
1899  uuid=$(cat /proc/sys/kernel/random/uuid 2>/dev/null)
1900  # If that does not work, then try uuidgen
1901  if [ ${#uuid} -ne 36 ]; then
1902    uuid=$(uuidgen 2>/dev/null)
1903  fi
1904  # Convert to lowercase
1905  uuid=$(echo "$uuid" | tr '[:upper:]' '[:lower:]')
1906  printf "$uuid"
1907}
1908
1909function generate_install_signature() {
1910  local install_id="$1"
1911  local install_type="$2"
1912  local install_time="$3"
1913  printf "{\"install_id\":\"$install_id\",\"install_type\":\"$install_type\",\"install_time\":$install_time}"
1914}
1915
1916install_id=$(generate_install_id)
1917install_time=$(date +%s)
1918
1919# If an install.json already exists, is formatted correctly, and was generated by this script,
1920# reuse the original install ID and time.
1921if [ -f "$etcdir/install.json" ]; then
1922  # Parse the JSON file using substring extraction to avoid a dependency on any JSON parser
1923  install_info=$($sudo_cmd cat "$etcdir/install.json" 2>/dev/null)
1924  if [ ${#install_info} -eq 118 ]; then
1925    if [ "${install_info:2:10}" == "install_id" ] && [ "${install_info:53:38}" == "\"install_type\":\"$install_type\"" ] && [ "${install_info:93:12}" == "install_time" ]; then
1926      install_id=${install_info:15:36}
1927      install_time=${install_info:107:10}
1928    fi
1929  fi
1930fi
1931
1932install_signature=$(generate_install_signature "$install_id" "$install_type" "$install_time")
1933
1934install_info_content="---
1935install_method:
1936  tool: install_script
1937  tool_version: $variant
1938  installer_version: install_script-$install_script_version
1939"
1940
1941if [ ! "$no_agent" ] && ! is_installed_by_installer "$sudo_cmd" "datadog-agent"; then
1942  $sudo_cmd sh -c "echo '$install_signature' > $etcdir/install.json"
1943  $sudo_cmd chmod 644 "$etcdir/install.json"
1944  $sudo_cmd sh -c "exec cat > $etcdir/install_info " <<EOF
1945$install_info_content
1946EOF
1947fi
1948
1949if [ -n "$fips_mode" ]; then
1950  # Creating or overriding the install information
1951  $sudo_cmd sh -c "echo '$install_info_content' > $etcdirfips/install_info"
1952fi
1953
1954# On SUSE 11, sudo service datadog-agent start fails (because /sbin is not in a base user's path)
1955# However, sudo /sbin/service datadog-agent does work.
1956# Use which (from root user) to find the absolute path to service
1957
1958service_cmd="service"
1959if [ "$SUSE11" == "yes" ]; then
1960  # We're testing SLES11 on a opensuse 13.2, `which service` will fail on openSUSE 13.2 and needs to have `service` as a default value
1961  service_cmd=$($sudo_cmd which service || echo "service")
1962fi
1963
1964declare -a monitoring_services
1965monitoring_services=( "datadog-agent" )
1966
1967##
1968# START THE AGENT
1969##
1970if [ -n "$no_start" ]; then
1971  printf "\033[34m\n  * DD_INSTALL_ONLY environment variable set.\033[0m\n"
1972fi
1973
1974for current_service in "${services[@]}"; do
1975    nice_current_flavor=$(getMapData flavor_to_readable "$current_service")
1976
1977  # Use /usr/sbin/service by default.
1978  # Some distros usually include compatibility scripts with Upstart or Systemd. Check with: `command -v service | xargs grep -E "(upstart|systemd)"`
1979  restart_cmd="$sudo_cmd $service_cmd $current_service restart"
1980  stop_instructions="$sudo_cmd $service_cmd $current_service stop"
1981  start_instructions="$sudo_cmd $service_cmd $current_service start"
1982
1983  if [[ $($sudo_cmd ps --no-headers -o comm 1 2>&1) == "systemd" ]] && command -v systemctl 2>&1; then
1984    # Use systemd if systemctl binary exists and systemd is the init process
1985    restart_cmd="$sudo_cmd systemctl restart ${current_service}.service"
1986    stop_instructions="$sudo_cmd systemctl stop $current_service"
1987    start_instructions="$sudo_cmd systemctl start $current_service"
1988  elif /sbin/init --version 2>&1 | grep -q upstart; then
1989    # Try to detect Upstart, this works most of the times but still a best effort
1990    restart_cmd="$sudo_cmd stop $current_service || true ; sleep 2s ; $sudo_cmd start $current_service"
1991    stop_instructions="$sudo_cmd stop $current_service"
1992    start_instructions="$sudo_cmd start $current_service"
1993  fi
1994
1995  if [ -n "$no_start" ]; then
1996    # It is possible that services were started during the installation phase, for example on CentOS7 (systemd < v237)
1997    # In that case, we should stop them
1998    running=0
1999    for s in "${running_services[@]}"; do
2000      if [[ "$s" == "$current_service" ]]; then
2001        running=1
2002        break
2003      fi
2004    done
2005
2006    if [[ $running -eq 0 ]]; then
2007      printf "\033[34m\n  Stopping service ${current_service} that was launched during the package installation.\033[0m\n"
2008      $stop_instructions || true
2009      if [[ $current_service == "datadog-agent" ]]; then
2010        # Stop all the related services
2011        # https://github.com/DataDog/datadog-agent/blob/def18e3815c6cc67d8669408032961804821687a/omnibus/package-scripts/agent-rpm/preinst#L16-L20
2012        eval "${stop_instructions}-process || true"
2013        eval "${stop_instructions}-sysprobe || true"
2014        eval "${stop_instructions}-trace || true"
2015        eval "${stop_instructions}-security || true"
2016      fi
2017    fi
2018
2019    printf "\033[34m\n    The newly installed version of the ${nice_current_flavor} will not be started.
2020    You will have to do it manually using the following command:
2021
2022    $start_instructions\033[0m\n\n"
2023
2024    continue
2025  fi
2026
2027  printf "\033[34m* Starting the ${nice_current_flavor}...\n\033[0m\n"
2028  ERROR_MESSAGE="Error starting ${nice_current_flavor}"
2029
2030  eval "$restart_cmd"
2031
2032  ERROR_MESSAGE=""
2033
2034  # Metrics are submitted, echo some instructions and exit
2035  printf "\033[32m  Your ${nice_current_flavor} is running and functioning properly.\n\033[0m"
2036
2037  if [[ "${monitoring_services[*]}" =~ ${current_service} ]]; then
2038    printf "\033[32m  It will continue to run in the background and submit metrics to Datadog.\n\033[0m"
2039  fi
2040
2041  printf "\033[32m  If you ever want to stop the ${nice_current_flavor}, run:
2042
2043      $stop_instructions
2044
2045  And to run it again run:
2046
2047      $start_instructions\033[0m\n\n"
2048
2049  docker_config_dir="/etc/docker"
2050  if [ -d "$docker_config_dir" ]; then
2051    groups dd-agent 2>&1 | grep -v docker > /dev/null && printf "\033[32m  Consider adding dd-agent to the docker group to enable the docker support, run:
2052
2053      sudo usermod -a -G docker dd-agent\033[0m\n\n"
2054  fi
2055done
2056
2057report_telemetry "$install_id" "$install_type" "$install_time"