├── README.md ├── status ├── status.css └── status.html ├── k8sensor_uninstall ├── k8sensor ├── LICENSE ├── connector └── agent /README.md: -------------------------------------------------------------------------------- 1 | # aiops-insights-tools 2 | public tools for IBM AIops Insights project 3 | -------------------------------------------------------------------------------- /status/status.css: -------------------------------------------------------------------------------- 1 | html, 2 | body { 3 | font-family: 'IBM Plex Sans', 'Helvetica Neue', Arial, sans-serif; 4 | background: #f4f4f4; 5 | margin: 0; 6 | } 7 | .header { 8 | background: black; 9 | color: #ffffff; 10 | height: 3rem; 11 | display: flex; 12 | align-items: center; 13 | } 14 | 15 | .header-company-name { 16 | margin-left: 1rem; 17 | font-size: 14px; 18 | display: inline-block; 19 | } 20 | 21 | .header-product-name { 22 | font-size: 14px; 23 | font-weight: 600; 24 | display: inline-block; 25 | } 26 | 27 | .title { 28 | background: white; 29 | height: 9rem; 30 | display: flex; 31 | align-items: center; 32 | } 33 | 34 | .title-text { 35 | margin-left: 2rem; 36 | font-size: 32px; 37 | } 38 | 39 | .status { 40 | background: white; 41 | margin: 1rem; 42 | padding: 1rem; 43 | } 44 | 45 | .status-text { 46 | padding-top: 12px; 47 | font-size: 24px; 48 | } 49 | 50 | .upcoming-maintenance { 51 | background: white; 52 | margin: 1rem; 53 | padding: 1rem; 54 | } 55 | 56 | .upcoming-maintenance-text { 57 | padding-top: 12px; 58 | font-size: 24px; 59 | } -------------------------------------------------------------------------------- /status/status.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | IBM AIOps Insights Status 5 | 6 | 7 | 8 | 9 |
10 |
11 | IBM 12 |
13 |
14 | AIOps Insights Status 15 |
16 |
17 |
18 |
19 | Health status 20 |
21 |
22 |
23 |
24 | System status 25 |
26 |
27 | 28 |
29 |
30 |
31 |
32 | Upcoming scheduled maintenance 33 |
34 |
35 | 36 |
37 |
38 | 39 | 40 | -------------------------------------------------------------------------------- /k8sensor_uninstall: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | service_prefix="insight-k8sensor" 4 | suffix=".config" 5 | config_path="/opt/instana/agent/k8sensor/etc/" 6 | CONTAINER_ENGINE=podman 7 | 8 | function exists { 9 | if which "$1" >/dev/null 2>&1; then 10 | return 0 11 | else 12 | return 1 13 | fi 14 | } 15 | 16 | # Check if config_path exists and is a directory 17 | if [ ! -d "$config_path" ]; then 18 | echo "Directory $config_path does not exist." 19 | exit 1 20 | fi 21 | 22 | # Check if there are any files with the given suffix 23 | shopt -s nullglob 24 | filelist=("$config_path"/*"$suffix") 25 | if [ ${#filelist[@]} -eq 0 ]; then 26 | echo "No files with suffix $suffix found in $config_path." 27 | exit 1 28 | fi 29 | 30 | # Check Podman 31 | if ! exists $CONTAINER_ENGINE; then 32 | echo "$CONTAINER_ENGINE is not installed." 33 | exit 1 34 | fi 35 | 36 | 37 | for filepath in "$config_path"/*"$suffix"; do 38 | filename=$(basename "$filepath") 39 | service="${filename%$suffix}" 40 | 41 | echo "Stop the service: ${service_prefix}-${service}.service" 42 | systemctl stop -q ${service_prefix}-${service}.service > /dev/null 2>&1 43 | systemctl disable -q ${service_prefix}-${service}.service > /dev/null 2>&1 44 | systemctl reset-failed -q > /dev/null 2>&1 45 | systemctl daemon-reload -q > /dev/null 2>&1 46 | 47 | $CONTAINER_ENGINE stop "${service_prefix}-${service}" > /dev/null 2>&1 48 | $CONTAINER_ENGINE rm "${service_prefix}-${service}" > /dev/null 2>&1 49 | 50 | echo "Removing /etc/systemd/system/${service_prefix}-${service}.service" 51 | rm /etc/systemd/system/${service_prefix}-${service}.service > /dev/null 2>&1 52 | echo "Removing /opt/instana/agent/etc/k8sensor/${service}.config" 53 | rm "/opt/instana/agent/etc/k8sensor/${service}.config" > /dev/null 2>&1 54 | done 55 | 56 | # Reset nullglob back to its default state 57 | shopt -u nullglob 58 | -------------------------------------------------------------------------------- /k8sensor: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | function log_error { 4 | local message=$1 5 | 6 | if [[ $TERM == *"color"* ]]; then 7 | echo -e "\e[31m$message\e[0m" 8 | else 9 | echo "${message}" 10 | fi 11 | } 12 | 13 | function log_info { 14 | local message=$1 15 | 16 | if [[ $TERM == *"color"* ]]; then 17 | echo -e "\e[32m$message\e[0m" 18 | else 19 | echo "${message}" 20 | fi 21 | } 22 | 23 | function log_debug { 24 | local message=$1 25 | 26 | if [[ $TERM == *"color"* ]]; then 27 | echo -e "\e[33m${message}\e[0m" 28 | else 29 | echo "${message}" 30 | fi 31 | } 32 | 33 | function exists { 34 | if which "$1" >/dev/null 2>&1; then 35 | return 0 36 | else 37 | return 1 38 | fi 39 | } 40 | 41 | # Check if the correct number of arguments was provided 42 | if [[ $# -lt 4 ]] || [[ $# -gt 5 ]]; then 43 | echo "NOTE: You should run the command with sudo as it starts the systemd service." 44 | echo "Usage: $0 " 45 | echo ": The url of the K8S cluster to be monitored. e.g. \"https://console-openshift-console.apps.bowings.cp.fyre.ibm.com:6443\"" 46 | echo ": The OAuth token for the user or serviceaccount." 47 | echo ": The AIOps Insight Backend URL. e.g. 'https://connector.apps.itom-dev-2.vjgp.p1.openshiftapps.com:443'" 48 | echo ": The key for the AIOps Insight Backend." 49 | echo ": The zone name to represent the K8S cluster on the UI. e.g. 'my-k8s'" 50 | exit 1 51 | fi 52 | 53 | # Assign arguments to variables 54 | AGENT_DIR="/opt/instana/agent" 55 | CONTAINER_ENGINE=podman 56 | K8SENSOR_IMAGE="icr.io/instana/k8sensor" 57 | MIN_PODMAN_VERSION=4 58 | K8SENSOR_SERVER=$1 59 | K8SENSOR_TOKEN=$2 60 | BACKEND=$3 61 | INSTANA_AGENT_KEY=$4 62 | K8SENSOR_CLUSTER_NAME=$5 63 | 64 | # Check Podman 65 | if ! exists $CONTAINER_ENGINE; then 66 | log_error "$CONTAINER_ENGINE is not installed. K8sensor service won't be installed." 67 | exit 1 68 | fi 69 | 70 | # Get the Podman version 71 | PODMAN_VERSION=$($CONTAINER_ENGINE --version | awk '{print $3}') 72 | 73 | # Extract major version 74 | MAJOR_VERSION=$(echo "${PODMAN_VERSION}" | cut -d '.' -f1) 75 | 76 | # Check if the major version is less than minimum version 77 | if [ "${MAJOR_VERSION}" -lt "${MIN_PODMAN_VERSION}" ]; then 78 | log_error "Error: Podman version is less than ${MIN_PODMAN_VERSION} (version found: $PODMAN_VERSION)." 79 | exit 1 80 | fi 81 | 82 | 83 | # Check for Systemd 84 | init_system=$(ps --no-headers -o comm 1) 85 | 86 | if [[ "${init_system,,}" != "systemd" ]]; then 87 | log_error "The init system is not systemd (it's ${init_system}). K8sensor service won't be installed." 88 | exit 1 89 | fi 90 | 91 | 92 | log_info "Preprocess the inputs" 93 | HOSTNAME=$(echo "$K8SENSOR_SERVER" | awk -F[/:] '{print $4}') #extract hostname 94 | PORT=$(echo "$K8SENSOR_SERVER" | awk -F[/:] '{print $5}') #extract post 95 | 96 | # Check if a port was included in the URL; if not, set a default port 97 | if [ -z "$PORT" ]; then 98 | PORT="6443" # default port for Kubernetes API server 99 | fi 100 | 101 | 102 | # BACKEND="https://${INSTANA_AGENT_HOST#*.}:${INSTANA_AGENT_PORT}" # remove the tenant and unit from the backend url 103 | SERVER="${HOSTNAME}:${PORT}" 104 | CONFIG_FOLDER="${AGENT_DIR}/k8sensor/etc" 105 | mkdir -p ${CONFIG_FOLDER} 106 | KUBE_CONFIG_PATH="${CONFIG_FOLDER}/${HOSTNAME}.config" #The kube.config path. Might not work for non-linux system 107 | SYSTEMD_SERVICE_NAME="insight-k8sensor-${HOSTNAME}" 108 | SYSTEMD_CONFIG_PATH="${CONFIG_FOLDER}/${SYSTEMD_SERVICE_NAME}.service" 109 | 110 | if [[ -n $INSIGHT_K8SENSOR_DEBUG ]] && [[ $INSIGHT_K8SENSOR_DEBUG == "True" ]]; then 111 | log_debug "***********************************************" 112 | log_debug K8SENSOR_SERVER=$K8SENSOR_SERVER 113 | log_debug K8SENSOR_TOKEN=$K8SENSOR_TOKEN 114 | log_debug BACKEND=$BACKEND 115 | log_debug INSTANA_AGENT_KEY=$INSTANA_AGENT_KEY 116 | log_debug K8SENSOR_CLUSTER_NAME=$K8SENSOR_CLUSTER_NAME 117 | log_debug SERVER=$SERVER 118 | log_debug CONFIG_FOLDER=$CONFIG_FOLDER 119 | log_debug KUBE_CONFIG_PATH=$KUBE_CONFIG_PATH 120 | log_debug SYSTEMD_SERVICE_NAME=$SYSTEMD_SERVICE_NAME 121 | log_debug SYSTEMD_CONFIG_PATH=$SYSTEMD_CONFIG_PATH 122 | log_debug "***********************************************" 123 | fi 124 | 125 | 126 | # Check if the service is running 127 | if systemctl is-active --quiet "$SYSTEMD_SERVICE_NAME"; then 128 | log_info "An existing service $SYSTEMD_SERVICE_NAME is running. k8sensor service won't be installed." 129 | log_info "You can run 'sudo systemctl stop $SYSTEMD_SERVICE_NAME' first if you want to reinstall the service." 130 | exit 0 131 | fi 132 | 133 | log_info "Pull the latest image" 134 | $CONTAINER_ENGINE pull $K8SENSOR_IMAGE:"latest" 135 | 136 | # Check if the container is running 137 | if [ "$($CONTAINER_ENGINE ps -q -f name=${SYSTEMD_SERVICE_NAME})" ]; then 138 | # Stop the container 139 | log_info "Stop the container ${SYSTEMD_SERVICE_NAME}" 140 | $CONTAINER_ENGINE stop "${SYSTEMD_SERVICE_NAME}" > /dev/null 2>&1 141 | fi 142 | 143 | # Check if the container exists and is not running, then remove it 144 | if [ "$($CONTAINER_ENGINE ps -aq -f status=exited -f name=${SYSTEMD_SERVICE_NAME})" ]; then 145 | # Remove the stopped container 146 | log_info "Remove the container ${SYSTEMD_SERVICE_NAME}" 147 | $CONTAINER_ENGINE rm "${SYSTEMD_SERVICE_NAME}" > /dev/null 2>&1 148 | fi 149 | 150 | KUBECONFIG_CONTENT=$(cat < "$KUBE_CONFIG_PATH" 174 | 175 | log_info "Try running the k8sensor containers ${SYSTEMD_SERVICE_NAME}" 176 | if [[ -n $K8SENSOR_CLUSTER_NAME ]]; then 177 | $CONTAINER_ENGINE run --name="${SYSTEMD_SERVICE_NAME}" -d -v "$KUBE_CONFIG_PATH":/root/config:ro $K8SENSOR_IMAGE -backend "$BACKEND" -key "$INSTANA_AGENT_KEY" -kubeconfig /root/config -zone "$K8SENSOR_CLUSTER_NAME" 178 | else 179 | $CONTAINER_ENGINE run --name="${SYSTEMD_SERVICE_NAME}" -d -v "$KUBE_CONFIG_PATH":/root/config:ro $K8SENSOR_IMAGE -backend "$BACKEND" -key "$INSTANA_AGENT_KEY" -kubeconfig /root/config 180 | fi 181 | 182 | # If the configuration is wrong, it should fail quickly 183 | sleep 10 184 | 185 | if ! $CONTAINER_ENGINE ps | grep -q "$SYSTEMD_SERVICE_NAME"; then 186 | log_error "No container is running from the image $SYSTEMD_SERVICE_NAME." 187 | log_error "Need to debug from the logs 'podman logs $SYSTEMD_SERVICE_NAME'" 188 | log_error "K8sensor service won't be installed." 189 | exit 1 190 | fi 191 | 192 | 193 | log_info "Convert the container to systemd service" 194 | $CONTAINER_ENGINE generate systemd --new --name "${SYSTEMD_SERVICE_NAME}" --container-prefix "k8sensor" > "${SYSTEMD_CONFIG_PATH}" 195 | 196 | log_info "Stop the container" 197 | $CONTAINER_ENGINE stop "${SYSTEMD_SERVICE_NAME}" 198 | 199 | log_info "Remove the container" 200 | $CONTAINER_ENGINE rm "${CONTAINER_NAME}" > /dev/null 2>&1 201 | 202 | log_info "Add the service to systemd" 203 | cp "${SYSTEMD_CONFIG_PATH}" /etc/systemd/system/ 204 | 205 | log_info "Reload the service list" 206 | systemctl daemon-reload 207 | 208 | log_info "Enable the service: ${SYSTEMD_SERVICE_NAME}.service" 209 | systemctl enable "${SYSTEMD_SERVICE_NAME}.service" 210 | 211 | log_info "Start the service: ${SYSTEMD_SERVICE_NAME}.service" 212 | systemctl start "${SYSTEMD_SERVICE_NAME}.service" 213 | 214 | # keep the service running when user logged out 215 | loginctl enable-linger 216 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /connector: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | ### 3 | ### Copyright 2019, Instana Inc. 4 | ### 5 | ### Licensed under the Apache License, Version 2.0 (the "License"); 6 | ### you may not use this file except in compliance with the License. 7 | ### You may obtain a copy of the License at 8 | ### 9 | ### http://www.apache.org/licenses/LICENSE-2.0 10 | ### 11 | ### Unless required by applicable law or agreed to in writing, software 12 | ### distributed under the License is distributed on an "AS IS" BASIS, 13 | ### WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | ### See the License for the specific language governing permissions and 15 | ### limitations under the License. 16 | ### 17 | 18 | set -o pipefail 19 | 20 | AGENT_DIR="/opt/instana/agent" 21 | # AIX, Darwin, Linux, SunOS 22 | OS=$(uname -s) 23 | MACHINE="" 24 | FAMILY="unknown" 25 | INIT="sysv" 26 | 27 | PKG_URI=packages.instana.io 28 | 29 | AGENT_TYPE="dynamic" 30 | OPEN_J9="false" 31 | PROMPT=true 32 | START=false 33 | LOCATION= 34 | ENDPOINT="" 35 | MODE="apm" 36 | GIT_REPO= 37 | GIT_BRANCH= 38 | GIT_USERNAME= 39 | GIT_PASSWORD= 40 | INSTANA_AGENT_SYSTEMD_TYPE=simple 41 | 42 | INSTANA_AGENT_KEY="$INSTANA_AGENT_KEY" 43 | INSTANA_DOWNLOAD_KEY="$INSTANA_DOWNLOAD_KEY" 44 | INSTANA_AGENT_HOST="$INSTANA_AGENT_HOST" 45 | INSTANA_AGENT_PORT="${INSTANA_AGENT_PORT:-443}" 46 | 47 | INSTANA_AWS_REGION_CONFIG="" 48 | 49 | gpg_check=1 50 | 51 | function exists { 52 | if which "$1" >/dev/null 2>&1; then 53 | return 0 54 | else 55 | return 1 56 | fi 57 | } 58 | 59 | download_command='none' 60 | 61 | function download_to_stdout { 62 | case "${download_command}" in 63 | 'curl') 64 | download_to_stdout_curl $@ 65 | ;; 66 | 'wget') 67 | download_to_stdout_wget $@ 68 | ;; 69 | *) 70 | log_error "Unknown download command '${download_command}'" 71 | exit 1; 72 | esac 73 | } 74 | 75 | function download_to_stdout_curl { 76 | local url="$1" 77 | # Auth is passed in curl format: : 78 | local authentication="$2" 79 | local authentication_parameters 80 | # Connection timeout, default 2 secs 81 | local connect_timeout="${3:-2}" 82 | 83 | if [ -n "${authentication}" ]; then 84 | authentication_parameters="-u ${authentication}" 85 | fi 86 | 87 | if curl -s --fail --connect-timeout "${connect_timeout}" ${authentication_parameters} "${url}"; then 88 | return 0 89 | else 90 | return $? 91 | fi 92 | } 93 | 94 | function download_to_stdout_wget { 95 | local url="$1" 96 | # Auth is passed in curl format: : 97 | local authentication="$2" 98 | local authentication_parameters 99 | # Connection timeout, default 2 secs 100 | local connect_timeout="${3:-2}" 101 | 102 | if [ -n "${authentication}" ]; then 103 | local username; 104 | username=$(awk -F ':' '{ print $1}' <<< "${authentication}") 105 | 106 | local password 107 | password=$(awk -F ':' '{ print $2}' <<< "${authentication}") 108 | 109 | authentication_parameters="--auth-no-challenge --http-user=${username} --http-password=${password}" 110 | fi 111 | 112 | if wget --timeout="${connect_timeout}" -qO- ${authentication_parameters} "${url}"; then 113 | return 0 114 | else 115 | return $? 116 | fi 117 | } 118 | 119 | function log_error { 120 | local message=$1 121 | 122 | if [[ $TERM == *"color"* ]]; then 123 | echo -e "\e[31m$message\e[0m" 124 | else 125 | echo $message 126 | fi 127 | } 128 | 129 | function log_info { 130 | local message=$1 131 | 132 | if [[ $TERM == *"color"* ]]; then 133 | echo -e "\e[32m$message\e[0m" 134 | else 135 | echo $message 136 | fi 137 | } 138 | 139 | function log_warn { 140 | local message=$1 141 | 142 | if [[ $TERM == *"color"* ]]; then 143 | echo -e "\e[33m${message}\e[0m" 144 | else 145 | echo "${message}" 146 | fi 147 | } 148 | 149 | function receive_confirmation() { 150 | read -r -p "$1 [y/N] " response 151 | 152 | if [[ ! $response =~ ^([yY][eE][sS]|[yY])$ ]]; then 153 | return 1 154 | fi 155 | 156 | return 0 157 | } 158 | 159 | function check_prerequisites() { 160 | if exists curl; then 161 | download_command='curl' 162 | elif exists wget; then 163 | download_command='wget' 164 | else 165 | log_error 'This script requires either curl or wget to be installed on this system. Aborting installation.' 166 | exit 1 167 | fi 168 | 169 | if ! which gpg > /dev/null 2>&1; then 170 | log_warn 'The "gpg" program is not installed on this system: the verification of the Instana agent packages cannot be performed.' 171 | if [ $PROMPT = true ]; then 172 | if ! receive_confirmation 'Do you want to continue?'; then 173 | exit 1 174 | fi 175 | fi 176 | 177 | log_warn 'The verification of the Instana agent packages will be skipped.' 178 | gpg_check=0 179 | fi 180 | } 181 | 182 | function check_download_key() { 183 | # Retry the download-key check a few times with increasing timeout as this appeared to be unreliable at times 184 | # Timeout is identified by exit code 28 for curl, and 4 for wget. 185 | local retval 186 | local n=1 187 | while : 188 | do 189 | # Use an increasing timeout of "n*3" seconds 190 | download_to_stdout "https://${PKG_URI}/agent/generic/x86_64/repodata/repomd.xml" "_:${INSTANA_DOWNLOAD_KEY}" $((n * 3)) > /dev/null 2>&1 191 | retval=$? 192 | 193 | [ ${retval} -ne 28 ] && [ ${retval} -ne 4 ] && break || n=$((n + 1)) 194 | [ ${n} -ge 5 ] && break 195 | 196 | done 197 | 198 | if [ ${retval} -eq 28 ] || [ ${retval} -eq 4 ]; then 199 | log_error "Verifying the Instana agent download key timed-out, please try again." 200 | exit 1 201 | elif [ ${retval} -ne 0 ]; then 202 | log_error "The Instana agent download key provided seems to be invalid, please check the agent key and try again." 203 | exit 1 204 | fi 205 | } 206 | 207 | function detect_family() { 208 | if which apt-get &> /dev/null; then 209 | FAMILY="apt" 210 | return 0 211 | fi 212 | 213 | if type dnf &>/dev/null 214 | then 215 | FAMILY="dnf" 216 | return 0 217 | fi 218 | 219 | if type yum &>/dev/null 220 | then 221 | FAMILY="yum" 222 | return 0 223 | fi 224 | 225 | if which zypper &> /dev/null; then 226 | FAMILY="zypper" 227 | return 0 228 | fi 229 | } 230 | 231 | function detect_init() { 232 | if ls -l /sbin/init | grep systemd &> /dev/null; then 233 | INIT="systemd" 234 | return 0 235 | fi 236 | 237 | if /sbin/init --version | grep upstart &> /dev/null; then 238 | INIT="upstart" 239 | return 0 240 | fi 241 | } 242 | 243 | function detect_machine() { 244 | if [ "$OS" = "AIX" ]; then 245 | MACHINE=$(uname -p) 246 | elif [ "$OS" = "Darwin" ]; then 247 | MACHINE=$(uname -m) 248 | elif [ "$OS" = "Linux" ]; then 249 | MACHINE=$(uname -m) 250 | elif [ "$OS" = "SunOS" ]; then 251 | MACHINE=$(uname -m) 252 | else 253 | log_info "Could not detect machine for OS: $OS" 254 | MACHINE="unknown" 255 | fi 256 | } 257 | 258 | function get_endpoint() { 259 | if [ -n "${ENDPOINT}" ]; then 260 | local split=(${ENDPOINT//:/ }) 261 | INSTANA_AGENT_HOST="${split[0]}" 262 | INSTANA_AGENT_PORT="${split[1]}" 263 | elif [[ "${LOCATION}" == "eu" ]]; then 264 | INSTANA_AGENT_HOST="saas-eu-west-1.instana.io" 265 | elif [[ "${LOCATION}" == "us" ]]; then 266 | INSTANA_AGENT_HOST="saas-us-west-2.instana.io" 267 | elif [[ "${LOCATION}" == "red" ]]; then 268 | INSTANA_AGENT_HOST="ingress-red-saas.instana.io" 269 | elif [[ "${LOCATION}" == "blue" ]]; then 270 | INSTANA_AGENT_HOST="ingress-blue-saas.instana.io" 271 | elif [[ "${LOCATION}" == "green" ]]; then 272 | INSTANA_AGENT_HOST="ingress-green-saas.instana.io" 273 | fi 274 | } 275 | 276 | function use_internal_packages () { 277 | if [ "${USE_INTERNAL_PACKAGES}" = 'true' ]; then 278 | local MVN_CFG_FILE='/opt/instana/agent/etc/org.ops4j.pax.url.mvn.cfg' 279 | log_info "Configuring internal repository usage in ${MVN_CFG_FILE} file" 280 | sed -i 's/features-public@id=features/features-internal@id=features/' "${MVN_CFG_FILE}" 281 | fi 282 | } 283 | 284 | function setup_agent() { 285 | local gpg_uri="https://${PKG_URI}/Instana.gpg" 286 | 287 | case "$FAMILY" in 288 | 289 | 'apt') 290 | 291 | log_info "Setting up Instana APT repository" 292 | 293 | # For whatever reason debian uses rando arch names instead of what is reported by uname 294 | local arch="$MACHINE" 295 | 296 | case "${MACHINE}" in 297 | 298 | 'x86_64') 299 | arch='amd64' 300 | ;; 301 | 302 | 'aarch64') 303 | arch='arm64' 304 | ;; 305 | 306 | 'ppc64le') 307 | arch='ppc64el' 308 | ;; 309 | 310 | esac 311 | 312 | local INSTANA_AUTH_CONF_FILE='/etc/apt/auth.conf.d/instana-packages.conf' 313 | if [ -d "$(dirname "${INSTANA_AUTH_CONF_FILE}")" ]; then 314 | # We should use /etc/apt/auth.conf.d rather than hard-coding the credentials in the `apt url`. 315 | if ! echo "machine ${PKG_URI} 316 | login _ 317 | password ${INSTANA_DOWNLOAD_KEY} 318 | " > "${INSTANA_AUTH_CONF_FILE}"; then 319 | log_error "Cannot create the ${INSTANA_AUTH_CONF_FILE} file to configure authentication for the ${PKG_URI} repository" 320 | exit 1 321 | fi 322 | 323 | log_info "Authentication for the ${PKG_URI} repository has been added to apt via the ${INSTANA_AUTH_CONF_FILE} file" 324 | 325 | local apt_uri="deb [arch=${arch}] https://${PKG_URI}/agent/deb generic main" 326 | else 327 | local apt_uri="deb [arch=${arch}] https://_:${INSTANA_DOWNLOAD_KEY}@${PKG_URI}/agent/deb generic main" 328 | fi 329 | 330 | if ! echo "$apt_uri" > /etc/apt/sources.list.d/instana-agent.list; then 331 | log_error "Instana APT repository setup failed" 332 | exit 1 333 | fi 334 | 335 | if [ "${gpg_check}" -eq 1 ]; then 336 | log_info "Importing Instana GPG key" 337 | if ! download_to_stdout "$gpg_uri" | apt-key add - > /dev/null; then 338 | log_error "Instana GPG key import failed" 339 | exit 1 340 | fi 341 | else 342 | AUTHENTICATION_PARAM='--allow-unauthenticated -o Acquire::AllowInsecureRepositories=true' 343 | fi 344 | 345 | log_info "Updating apt metadata" 346 | 347 | if ! apt-get ${AUTHENTICATION_PARAM} update -o Dir::Etc::sourcelist="sources.list.d/instana-agent.list" -o Dir::Etc::sourceparts="-" -o APT::Get::List-Cleanup="0" > /dev/null; then 348 | log_error "APT repository metadata update failed" 349 | exit 1 350 | fi 351 | 352 | log_info "Installing Instana agent" 353 | 354 | if ! apt-get ${AUTHENTICATION_PARAM} install -y instana-agent-${AGENT_TYPE} > /dev/null; then 355 | log_error "Instana agent package install failed" 356 | exit 1 357 | fi 358 | 359 | use_internal_packages 360 | ;; 361 | 362 | 'dnf') 363 | 364 | log_info "Setting up Instana RPM repository" 365 | 366 | local yum_repo 367 | read -r -d '' yum_repo < /etc/yum.repos.d/Instana-Agent.repo; then 379 | log_error "Instana YUM repository setup failed" 380 | exit 1 381 | fi 382 | 383 | log_info "Updating YUM metadata" 384 | if ! dnf makecache -y > /dev/null 2>&1; then 385 | log_error "YUM repository metadata update failed" 386 | exit 1 387 | fi 388 | 389 | log_info "Installing Instana agent" 390 | 391 | if ! dnf install -y instana-agent-$AGENT_TYPE > /dev/null; then 392 | log_error "Instana agent package install failed" 393 | exit 1 394 | fi 395 | 396 | use_internal_packages 397 | ;; 398 | 399 | 'yum') 400 | 401 | log_info "Setting up Instana YUM repository" 402 | 403 | local yum_repo 404 | read -r -d '' yum_repo < /etc/yum.repos.d/Instana-Agent.repo; then 416 | log_error "Instana YUM repository setup failed" 417 | exit 1 418 | fi 419 | 420 | log_info "Updating YUM metadata" 421 | if ! yum makecache -y fast > /dev/null 2>&1; then 422 | log_error "YUM repository metadata update failed" 423 | exit 1 424 | fi 425 | 426 | log_info "Installing Instana agent" 427 | 428 | if ! yum install -y instana-agent-$AGENT_TYPE > /dev/null; then 429 | log_error "Instana agent package install failed" 430 | exit 1 431 | fi 432 | 433 | use_internal_packages 434 | ;; 435 | 436 | 'zypper') 437 | 438 | log_info "Setting up Instana zypper repository" 439 | 440 | local zypp_repo 441 | read -r -d '' zypp_repo < /etc/zypp/repos.d/Instana-Agent.repo; then 453 | log_error "Instana zypper repository setup failed" 454 | exit 1 455 | fi 456 | 457 | if [ "${gpg_check}" -eq 1 ]; then 458 | log_info "Importing Instana GPG key" 459 | if ! rpm --import "$gpg_uri"; then 460 | log_error "Instana GPG key import failed" 461 | exit 1 462 | fi 463 | fi 464 | 465 | log_info "Updating zypper metadata" 466 | if ! zypper -n refresh Instana > /dev/null 2>&1; then 467 | log_error "zypper repository metadata update failed" 468 | exit 1 469 | fi 470 | 471 | log_info "Installing Instana agent" 472 | 473 | if ! zypper -n install instana-agent-$AGENT_TYPE > /dev/null; then 474 | log_error "Instana agent package install failed" 475 | exit 1 476 | fi 477 | 478 | use_internal_packages 479 | ;; 480 | 481 | *) 482 | log_error 'Unsupported package manager. The supported packages managers are: apt, dnf, yum, zypper' 483 | exit 1; 484 | 485 | esac 486 | 487 | } 488 | 489 | function configure_mode() { 490 | if [ "${MODE}" = 'apm' ]; then 491 | /bin/cp "${AGENT_DIR}/etc/instana/com.instana.agent.main.config.Agent.cfg.template" "${AGENT_DIR}/etc/instana/com.instana.agent.main.config.Agent.cfg" 492 | echo "mode = APM" >> "${AGENT_DIR}/etc/instana/com.instana.agent.main.config.Agent.cfg" 493 | 494 | return 0 495 | fi 496 | 497 | if [ "${MODE}" = 'aws' ]; then 498 | log_info 'Configuring AWS mode' 499 | # Get region from metadata endpoint 500 | 501 | if [ -n "${INSTANA_AWS_REGION_CONFIG}" ]; then 502 | log_info "Using the AWS region ${INSTANA_AWS_REGION_CONFIG} configured via the 'INSTANA_AWS_REGION_CONFIG' environment variable" 503 | export INSTANA_AWS_REGION_CONFIG 504 | elif ! INSTANA_AWS_REGION_CONFIG=$(download_to_stdout http://169.254.169.254/latest/dynamic/instance-identity/document | awk -F\" '/region/ {print $4}'); then 505 | log_error "Error querying AWS metadata. It seems this virtual machine is not running on EC2. Please set the 'INSTANA_AWS_REGION_CONFIG' environment variable manually." 506 | exit 1 507 | fi 508 | 509 | ROLES_FOUND=false 510 | 511 | if download_to_stdout http://169.254.169.254/latest/meta-data/iam/security-credentials/ > /dev/null 2>&1; then 512 | ROLES_FOUND=true 513 | fi 514 | 515 | if [ "$ROLES_FOUND" = "false" ]; then 516 | if [ -z "$AWS_ACCESS_KEY_ID" ] || [ -z "$AWS_SECRET_ACCESS_KEY" ]; then 517 | log_error "AWS_ACCESS_KEY_ID and/or AWS_SECRET_ACCESS_KEY not exported, and no IAM instance role detected to allow AWS API access." 518 | exit 1 519 | fi 520 | fi 521 | 522 | /bin/cp "${AGENT_DIR}/etc/instana/com.instana.agent.main.config.Agent.cfg.template" "${AGENT_DIR}/etc/instana/com.instana.agent.main.config.Agent.cfg" 523 | echo "mode = INFRASTRUCTURE" >> "${AGENT_DIR}/etc/instana/com.instana.agent.main.config.Agent.cfg" 524 | 525 | return 0 526 | fi 527 | 528 | if [ "$MODE" = "infra" ]; then 529 | /bin/cp "${AGENT_DIR}/etc/instana/com.instana.agent.main.config.Agent.cfg.template" "${AGENT_DIR}/etc/instana/com.instana.agent.main.config.Agent.cfg" 530 | echo "mode = INFRASTRUCTURE" >> "${AGENT_DIR}/etc/instana/com.instana.agent.main.config.Agent.cfg" 531 | 532 | return 0 533 | fi 534 | } 535 | 536 | function delete_git_repo() { 537 | rm -rf "${AGENT_DIR}/etc/.git" 538 | } 539 | 540 | function check_preexisting_git_repository() { 541 | if [ -n "${GIT_REPO}" ] && [ -d "${AGENT_DIR}/etc/.git" ]; then 542 | log_warn "The Git options have been specified, but there is already a Git repository in '${AGENT_DIR}/etc/.git'. To continue, we need to remove the current Git repository." 543 | 544 | if [ $PROMPT = true ]; then 545 | if receive_confirmation 'Do you want to continue?'; then 546 | delete_git_repo 547 | fi 548 | else 549 | delete_git_repo 550 | fi 551 | fi 552 | } 553 | 554 | function configure_env() { 555 | local env_content="" 556 | local env_path="" 557 | 558 | if [ "$INIT" = "systemd" ]; then 559 | env_path=/opt/instana/agent/etc/systemd.env 560 | else 561 | if [ "$FAMILY" = "zypper" ] || [ "$FAMILY" = "yum" ]; then 562 | env_path=/etc/sysconfig/instana-agent 563 | fi 564 | 565 | if [ "$FAMILY" = "apt" ]; then 566 | env_path=/etc/default/instana-agent 567 | fi 568 | fi 569 | 570 | [[ -n "$INSTANA_AWS_REGION_CONFIG" ]] && env_content+="$(get_env_line INSTANA_AWS_REGION_CONFIG $INSTANA_AWS_REGION_CONFIG)\n" 571 | [[ -n "$AWS_ACCESS_KEY_ID" ]] && env_content+="$(get_env_line AWS_ACCESS_KEY_ID $AWS_ACCESS_KEY_ID)\n" 572 | [[ -n "$AWS_SECRET_ACCESS_KEY" ]] && env_content+="$(get_env_line AWS_SECRET_ACCESS_KEY "$AWS_SECRET_ACCESS_KEY")\n" 573 | [[ -n "$GIT_REPO" && -n "$GIT_BRANCH" ]] && env_content+="$(get_env_line INSTANA_GIT_REMOTE_REPOSITORY "$GIT_REPO")\n$(get_env_line INSTANA_GIT_REMOTE_BRANCH "$GIT_BRANCH")\n" 574 | 575 | if [ -n "$GIT_USERNAME" ]; then 576 | env_content+="$(get_env_line INSTANA_GIT_REMOTE_USERNAME "$GIT_USERNAME")\n" 577 | if [ -n "$GIT_PASSWORD" ]; then 578 | env_content+="$(get_env_line INSTANA_GIT_REMOTE_PASSWORD "$GIT_PASSWORD")\n" 579 | else 580 | env_content+="$(get_env_line INSTANA_GIT_REMOTE_PASSWORD "")\n" 581 | fi 582 | fi 583 | 584 | printf "$env_content" > "$env_path" 585 | } 586 | 587 | function get_env_line() { 588 | local key=$1 589 | local val=$2 590 | 591 | if [ "$INIT" = "systemd" ]; then 592 | echo "${key}=${val}" 593 | else 594 | echo "export ${key}=${val}" 595 | fi 596 | } 597 | 598 | function update_custom_systemd_unit_file () { 599 | # file does not exists -> new installation indicator 600 | if [ "$INIT" = "systemd" ] && [ ! -e /lib/systemd/system/instana-agent.service ]; then 601 | mkdir -p /etc/systemd/system/instana-agent.service.d/ 602 | local systemd_custom_start_conf 603 | read -r -d '' systemd_custom_start_conf < /etc/systemd/system/instana-agent.service.d/agent-custom-start.conf; then 609 | log_warn "Failed to create '/etc/systemd/system/instana-agent.service.d/agent-custom-start.conf'" 610 | fi 611 | 612 | fi 613 | } 614 | 615 | 616 | function start_agent() { 617 | if systemctl is-active instana-agent > /dev/null 2>&1; then 618 | log_warn "Instana agent service is active and agent is reinstalled. Service will be restarted" 619 | START=true 620 | fi 621 | 622 | if [ $START = false ]; then 623 | return 0 624 | fi 625 | 626 | if [ "$INIT" = "systemd" ]; then 627 | if ! systemctl enable instana-agent > /dev/null 2>&1; then 628 | log_error "Instana agent service enable on boot failed" 629 | exit 1 630 | else 631 | log_info "Instana agent enabled on boot" 632 | fi 633 | 634 | log_info "Starting instana-agent" 635 | if ! systemctl restart instana-agent > /dev/null 2>&1; then 636 | log_error "Instana agent service start failed" 637 | exit 1 638 | else 639 | log_info "Instana agent service started up" 640 | fi 641 | else 642 | log_warn "Instana agent automatic enable/startup by this script is only supported for systemd" 643 | log_warn "Utilize your distribution's init system methods to enable/start the agent" 644 | fi 645 | } 646 | 647 | while getopts "syjinl:e:t:m:a:d:i:g:b:u:p:" opt; do 648 | case $opt in 649 | a) 650 | INSTANA_AGENT_KEY=$OPTARG 651 | ;; 652 | b) 653 | GIT_BRANCH=$OPTARG 654 | ;; 655 | l) 656 | LOCATION=$OPTARG 657 | ;; 658 | d) 659 | INSTANA_DOWNLOAD_KEY=$OPTARG 660 | ;; 661 | e) 662 | ENDPOINT=$OPTARG 663 | ;; 664 | g) 665 | GIT_REPO=$OPTARG 666 | ;; 667 | m) 668 | MODE=$OPTARG 669 | ;; 670 | n) 671 | INSTANA_AGENT_SYSTEMD_TYPE=notify 672 | ;; 673 | p) 674 | GIT_PASSWORD=$OPTARG 675 | ;; 676 | u) 677 | GIT_USERNAME=$OPTARG 678 | ;; 679 | s) 680 | START=true 681 | ;; 682 | i) 683 | USE_INTERNAL_PACKAGES=true 684 | ;; 685 | j) 686 | OPEN_J9="true" 687 | ;; 688 | t) 689 | AGENT_TYPE=$OPTARG 690 | # full and minimal are deprecated 691 | # remove this when the packages are removed 692 | if [ "$AGENT_TYPE" = "full" ]; then 693 | AGENT_TYPE=dynamic 694 | fi 695 | 696 | if [ "$AGENT_TYPE" = "minimal" ]; then 697 | AGENT_TYPE=dynamic 698 | fi 699 | ;; 700 | y) 701 | PROMPT=false 702 | ;; 703 | \?) 704 | echo "Invalid option: -$OPTARG" >&2 705 | exit 1 706 | ;; 707 | esac 708 | done 709 | 710 | if [ "$(id -u)" != "0" ]; then 711 | log_error "This script must be executed as a user with root privileges" 712 | exit 1 713 | fi 714 | 715 | if [ "$OS" = "Darwin" ]; then 716 | log_error "Agent install script does not support macOS. Please download the macOS package from the 'Installing Instana Agents' wizard." 717 | exit 1 718 | fi 719 | 720 | if [ "$OS" = "AIX" ]; then 721 | log_error "Agent install script does not support AIX. Please download the AIX package from the 'Installing Instana Agents' wizard." 722 | exit 1 723 | fi 724 | 725 | if [ "$OS" = "SunOS" ]; then 726 | log_error "Agent install script does not support Solaris. Please download the Solaris package from the 'Installing Instana Agents' wizard." 727 | exit 1 728 | fi 729 | 730 | detect_machine 731 | 732 | if [ $MACHINE != "x86_64" ] && [ $MACHINE != "aarch64" ] && [ $MACHINE != "s390x" ] && [ $MACHINE != "ppc64le" ]; then 733 | log_error "Systems architecture: $MACHINE not supported" 734 | exit 1 735 | fi 736 | 737 | if [ ! "$INSTANA_AGENT_KEY" ]; then 738 | echo "-a INSTANA_AGENT_KEY required!" 739 | exit 1 740 | fi 741 | 742 | if [ ! "$INSTANA_DOWNLOAD_KEY" ]; then 743 | INSTANA_DOWNLOAD_KEY="$INSTANA_AGENT_KEY" 744 | fi 745 | 746 | if [ $AGENT_TYPE != "static" ] && [ $AGENT_TYPE != "dynamic" ]; then 747 | log_error "Invalid agent type specified $AGENT_TYPE" 748 | exit 1 749 | fi 750 | 751 | if [ "$ENDPOINT" != "" ]; then 752 | if ! echo "$ENDPOINT" | grep ":" &>/dev/null; then 753 | log_error "Agent endpoint must be in the format of :" 754 | exit 1 755 | fi 756 | fi 757 | 758 | if [ -n "${LOCATION}" ]; then 759 | log_warn "The -l parameter is deprecated and will not be updated to cover new SaaS regions going forward. Use -e instead." 760 | if [ "${LOCATION}" != "eu" ] && [ "${LOCATION}" != "us" ] && [ "${LOCATION}" != "red" ] && [ "${LOCATION}" != "blue" ] && [ "${LOCATION}" != "green" ]; then 761 | log_error "Invalid location '${LOCATION}' specified. Please select 'blue', 'red' or 'green'." 762 | exit 1 763 | fi 764 | fi 765 | 766 | if [ "$MODE" != "apm" ] && [ "$MODE" != "aws" ] && [ "$MODE" != "infra" ]; then 767 | log_error "Invalid mode specified. Supported modes: apm | aws | infra." 768 | exit 1 769 | fi 770 | 771 | if [ $OPEN_J9 = "true" ] || [ $MACHINE = "ppc64le" ]; then 772 | AGENT_TYPE="${AGENT_TYPE}-j9" 773 | fi 774 | 775 | if [ ! "$INSTANA_DOWNLOAD_KEY" ]; then 776 | INSTANA_DOWNLOAD_KEY="$INSTANA_AGENT_KEY" 777 | fi 778 | 779 | if [ -n "${GIT_REPO}" ]; then 780 | if [ -z "${GIT_BRANCH}" ]; then 781 | log_error "The '-g' option for the Git repository has been specified without the '-b' option to specify the remote branch." 782 | exit 1 783 | fi 784 | else 785 | if [ -n "${GIT_BRANCH}" ]; then 786 | log_error "The '-b' option for the remote branch has been specified without the '-g' option to specify the Git repository." 787 | exit 1 788 | fi 789 | 790 | if [ -n "${GIT_USERNAME}" ]; then 791 | log_error "The '-u' option for the username to authenticate with has been specified without the '-g' option to specify the Git repository." 792 | exit 1 793 | fi 794 | 795 | if [ -n "${GIT_PASSWORD}" ]; then 796 | log_error "The '-p' option for the password to authenticate with has been specified without the '-g' option to specify the Git repository." 797 | exit 1 798 | fi 799 | fi 800 | 801 | if [ -n "${GIT_PASSWORD}" ]; then 802 | if [ -z "${GIT_USERNAME}" ]; then 803 | log_error "The '-p' option for the password to authenticate with has been specified without the '-u' option to specify the username." 804 | exit 1 805 | fi 806 | fi 807 | 808 | detect_family 809 | 810 | detect_init 811 | 812 | echo "Setting up the ${AGENT_TYPE} Instana agent for $OS" 813 | 814 | if [ $PROMPT = false ]; then 815 | response=y 816 | else 817 | if ! receive_confirmation "Are you sure?"; then 818 | exit 1 819 | fi 820 | fi 821 | 822 | check_prerequisites 823 | 824 | export INSTANA_AGENT_KEY 825 | export INSTANA_DOWNLOAD_KEY 826 | export INSTANA_AGENT_HOST 827 | export INSTANA_AGENT_PORT 828 | 829 | check_download_key 830 | 831 | get_endpoint 832 | 833 | 834 | update_custom_systemd_unit_file 835 | 836 | if ! setup_agent; then 837 | exit 1 838 | fi 839 | 840 | configure_mode 841 | 842 | check_preexisting_git_repository 843 | 844 | configure_env 845 | 846 | if ! start_agent; then 847 | exit 1 848 | fi 849 | -------------------------------------------------------------------------------- /agent: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ### 4 | ### Copyright 2019, Instana Inc. 5 | ### 6 | ### Licensed under the Apache License, Version 2.0 (the "License"); 7 | ### you may not use this file except in compliance with the License. 8 | ### You may obtain a copy of the License at 9 | ### 10 | ### http://www.apache.org/licenses/LICENSE-2.0 11 | ### 12 | ### Unless required by applicable law or agreed to in writing, software 13 | ### distributed under the License is distributed on an "AS IS" BASIS, 14 | ### WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | ### See the License for the specific language governing permissions and 16 | ### limitations under the License. 17 | ### 18 | 19 | set -o pipefail 20 | 21 | AGENT_DIR="/opt/instana/agent" 22 | # AIX, Darwin, Linux, SunOS 23 | OS=$(uname -s) 24 | MACHINE="" 25 | FAMILY="unknown" 26 | INIT="sysv" 27 | 28 | PKG_URI=packages.instana.io 29 | 30 | AGENT_TYPE="dynamic" 31 | OPEN_J9="false" 32 | PROMPT=true 33 | START=false 34 | LOCATION= 35 | ENDPOINT="" 36 | MODE="apm" 37 | GIT_REPO= 38 | GIT_BRANCH= 39 | GIT_USERNAME= 40 | GIT_PASSWORD= 41 | INSTANA_AGENT_SYSTEMD_TYPE=simple 42 | 43 | INSTANA_AGENT_KEY="$INSTANA_AGENT_KEY" 44 | INSTANA_DOWNLOAD_KEY="$INSTANA_DOWNLOAD_KEY" 45 | INSTANA_AGENT_HOST="$INSTANA_AGENT_HOST" 46 | INSTANA_AGENT_PORT="${INSTANA_AGENT_PORT:-443}" 47 | INSTANA_PRODUCT_NAME="aiops-insights" 48 | 49 | INSTANA_AWS_REGION_CONFIG="" 50 | 51 | gpg_check=1 52 | 53 | function exists { 54 | if which "$1" >/dev/null 2>&1; then 55 | return 0 56 | else 57 | return 1 58 | fi 59 | } 60 | 61 | download_command='none' 62 | 63 | function download_to_stdout { 64 | case "${download_command}" in 65 | 'curl') 66 | download_to_stdout_curl $@ 67 | ;; 68 | 'wget') 69 | download_to_stdout_wget $@ 70 | ;; 71 | *) 72 | log_error "Unknown download command '${download_command}'" 73 | exit 1; 74 | esac 75 | } 76 | 77 | function download_to_stdout_curl { 78 | local url="$1" 79 | # Auth is passed in curl format: : 80 | local authentication="$2" 81 | local authentication_parameters 82 | # Connection timeout, default 2 secs 83 | local connect_timeout="${3:-2}" 84 | 85 | if [ -n "${authentication}" ]; then 86 | authentication_parameters="-u ${authentication}" 87 | fi 88 | 89 | if curl -s --fail --connect-timeout "${connect_timeout}" ${authentication_parameters} "${url}"; then 90 | return 0 91 | else 92 | return $? 93 | fi 94 | } 95 | 96 | function download_to_stdout_wget { 97 | local url="$1" 98 | # Auth is passed in curl format: : 99 | local authentication="$2" 100 | local authentication_parameters 101 | # Connection timeout, default 2 secs 102 | local connect_timeout="${3:-2}" 103 | 104 | if [ -n "${authentication}" ]; then 105 | local username; 106 | username=$(awk -F ':' '{ print $1}' <<< "${authentication}") 107 | 108 | local password 109 | password=$(awk -F ':' '{ print $2}' <<< "${authentication}") 110 | 111 | authentication_parameters="--auth-no-challenge --http-user=${username} --http-password=${password}" 112 | fi 113 | 114 | if wget --timeout="${connect_timeout}" -qO- ${authentication_parameters} "${url}"; then 115 | return 0 116 | else 117 | return $? 118 | fi 119 | } 120 | 121 | function log_error { 122 | local message=$1 123 | 124 | if [[ $TERM == *"color"* ]]; then 125 | echo -e "\e[31m$message\e[0m" 126 | else 127 | echo $message 128 | fi 129 | } 130 | 131 | function log_info { 132 | local message=$1 133 | 134 | if [[ $TERM == *"color"* ]]; then 135 | echo -e "\e[32m$message\e[0m" 136 | else 137 | echo $message 138 | fi 139 | } 140 | 141 | function log_warn { 142 | local message=$1 143 | 144 | if [[ $TERM == *"color"* ]]; then 145 | echo -e "\e[33m${message}\e[0m" 146 | else 147 | echo "${message}" 148 | fi 149 | } 150 | 151 | function receive_confirmation() { 152 | read -r -p "$1 [y/N] " response 153 | 154 | if [[ ! $response =~ ^([yY][eE][sS]|[yY])$ ]]; then 155 | return 1 156 | fi 157 | 158 | return 0 159 | } 160 | 161 | function check_prerequisites() { 162 | if exists curl; then 163 | download_command='curl' 164 | elif exists wget; then 165 | download_command='wget' 166 | else 167 | log_error 'This script requires either curl or wget to be installed on this system. Aborting installation.' 168 | exit 1 169 | fi 170 | 171 | if ! which gpg > /dev/null 2>&1; then 172 | log_warn 'The "gpg" program is not installed on this system: the verification of the AIOps Insights agent packages cannot be performed.' 173 | if [ $PROMPT = true ]; then 174 | if ! receive_confirmation 'Do you want to continue?'; then 175 | exit 1 176 | fi 177 | fi 178 | 179 | log_warn 'The verification of the AIOps Insights agent packages will be skipped.' 180 | gpg_check=0 181 | fi 182 | } 183 | 184 | function check_download_key() { 185 | # Retry the download-key check a few times with increasing timeout as this appeared to be unreliable at times 186 | # Timeout is identified by exit code 28 for curl, and 4 for wget. 187 | local retval 188 | local n=1 189 | while : 190 | do 191 | # Use an increasing timeout of "n*3" seconds 192 | download_to_stdout "https://${PKG_URI}/agent/generic/x86_64/repodata/repomd.xml" "_:${INSTANA_DOWNLOAD_KEY}" $((n * 3)) > /dev/null 2>&1 193 | retval=$? 194 | 195 | [ ${retval} -ne 28 ] && [ ${retval} -ne 4 ] && break || n=$((n + 1)) 196 | [ ${n} -ge 5 ] && break 197 | 198 | done 199 | 200 | if [ ${retval} -eq 28 ] || [ ${retval} -eq 4 ]; then 201 | log_error "Verifying the AIOps Insights agent download key timed-out, please try again." 202 | exit 1 203 | elif [ ${retval} -ne 0 ]; then 204 | log_error "The AIOps Insights agent download key provided seems to be invalid, please check the download key and try again." 205 | exit 1 206 | fi 207 | } 208 | 209 | function detect_family() { 210 | if which apt-get &> /dev/null; then 211 | FAMILY="apt" 212 | return 0 213 | fi 214 | 215 | if type dnf &>/dev/null 216 | then 217 | FAMILY="dnf" 218 | return 0 219 | fi 220 | 221 | if type yum &>/dev/null 222 | then 223 | FAMILY="yum" 224 | return 0 225 | fi 226 | 227 | if which zypper &> /dev/null; then 228 | FAMILY="zypper" 229 | return 0 230 | fi 231 | } 232 | 233 | function detect_init() { 234 | if ls -l /sbin/init | grep systemd &> /dev/null; then 235 | INIT="systemd" 236 | return 0 237 | fi 238 | 239 | if /sbin/init --version | grep upstart &> /dev/null; then 240 | INIT="upstart" 241 | return 0 242 | fi 243 | } 244 | 245 | function detect_machine() { 246 | if [ "$OS" = "AIX" ]; then 247 | MACHINE=$(uname -p) 248 | elif [ "$OS" = "Darwin" ]; then 249 | MACHINE=$(uname -m) 250 | elif [ "$OS" = "Linux" ]; then 251 | MACHINE=$(uname -m) 252 | elif [ "$OS" = "SunOS" ]; then 253 | MACHINE=$(uname -m) 254 | else 255 | log_info "Could not detect machine for OS: $OS" 256 | MACHINE="unknown" 257 | fi 258 | } 259 | 260 | function get_endpoint() { 261 | if [ -n "${ENDPOINT}" ]; then 262 | local split=(${ENDPOINT//:/ }) 263 | INSTANA_AGENT_HOST="${split[0]}" 264 | INSTANA_AGENT_PORT="${split[1]}" 265 | elif [[ "${LOCATION}" == "eu" ]]; then 266 | INSTANA_AGENT_HOST="saas-eu-west-1.instana.io" 267 | elif [[ "${LOCATION}" == "us" ]]; then 268 | INSTANA_AGENT_HOST="saas-us-west-2.instana.io" 269 | elif [[ "${LOCATION}" == "red" ]]; then 270 | INSTANA_AGENT_HOST="ingress-red-saas.instana.io" 271 | elif [[ "${LOCATION}" == "blue" ]]; then 272 | INSTANA_AGENT_HOST="ingress-blue-saas.instana.io" 273 | elif [[ "${LOCATION}" == "green" ]]; then 274 | INSTANA_AGENT_HOST="ingress-green-saas.instana.io" 275 | fi 276 | } 277 | 278 | function use_internal_packages () { 279 | if [ "${USE_INTERNAL_PACKAGES}" = 'true' ]; then 280 | local MVN_CFG_FILE='/opt/instana/agent/etc/org.ops4j.pax.url.mvn.cfg' 281 | log_info "Configuring internal repository usage in ${MVN_CFG_FILE} file" 282 | sed -i 's/features-public@id=features/features-internal@id=features/' "${MVN_CFG_FILE}" 283 | fi 284 | } 285 | 286 | function check_existing_agent () { 287 | 288 | INSTANA_AGENT_INFO= 289 | case "$FAMILY" in 290 | 'apt') 291 | INSTANA_AGENT_INFO=$(dpkg -l | grep '^ii' | grep instana-agent-$AGENT_TYPE | awk '{print $2 " (" $3 ")"}') 292 | ;; 293 | 294 | 'dnf') 295 | INSTANA_AGENT_INFO=$(dnf list installed | grep instana-agent-$AGENT_TYPE | awk '{print $1 " (" $2 ")"}') 296 | ;; 297 | 298 | 'yum') 299 | INSTANA_AGENT_INFO=$(yum list installed | grep instana-agent-$AGENT_TYPE | awk '{print $1 " (" $2 ")"}') 300 | ;; 301 | 302 | 'zypper') 303 | INSTANA_AGENT_INFO=$(zypper se --installed-only | grep instana-agent-$AGENT_TYPE | awk '{print $3}') 304 | ;; 305 | 306 | esac 307 | 308 | if [[ -n "$INSTANA_AGENT_INFO" ]]; then 309 | echo "An existing Instana Agent is installed: $INSTANA_AGENT_INFO" 310 | echo "It will be updated to the current version." 311 | fi 312 | 313 | } 314 | 315 | function setup_agent() { 316 | local gpg_uri="https://${PKG_URI}/Instana.gpg" 317 | 318 | case "$FAMILY" in 319 | 320 | 'apt') 321 | 322 | log_info "Setting up AIOps Insights APT repository" 323 | 324 | # For whatever reason debian uses rando arch names instead of what is reported by uname 325 | local arch="$MACHINE" 326 | 327 | case "${MACHINE}" in 328 | 329 | 'x86_64') 330 | arch='amd64' 331 | ;; 332 | 333 | 'aarch64') 334 | arch='arm64' 335 | ;; 336 | 337 | 'ppc64le') 338 | arch='ppc64el' 339 | ;; 340 | 341 | esac 342 | 343 | local INSTANA_AUTH_CONF_FILE='/etc/apt/auth.conf.d/instana-packages.conf' 344 | if [ -d "$(dirname "${INSTANA_AUTH_CONF_FILE}")" ]; then 345 | # We should use /etc/apt/auth.conf.d rather than hard-coding the credentials in the `apt url`. 346 | if ! echo "machine ${PKG_URI} 347 | login _ 348 | password ${INSTANA_DOWNLOAD_KEY} 349 | " > "${INSTANA_AUTH_CONF_FILE}"; then 350 | log_error "Cannot create the ${INSTANA_AUTH_CONF_FILE} file to configure authentication for the ${PKG_URI} repository" 351 | exit 1 352 | fi 353 | 354 | log_info "Authentication for the ${PKG_URI} repository has been added to apt via the ${INSTANA_AUTH_CONF_FILE} file" 355 | 356 | local apt_uri="deb [arch=${arch}] https://${PKG_URI}/agent/deb generic main" 357 | else 358 | local apt_uri="deb [arch=${arch}] https://_:${INSTANA_DOWNLOAD_KEY}@${PKG_URI}/agent/deb generic main" 359 | fi 360 | 361 | if ! echo "$apt_uri" > /etc/apt/sources.list.d/instana-agent.list; then 362 | log_error "AIOps Insights APT repository setup failed" 363 | exit 1 364 | fi 365 | 366 | if [ "${gpg_check}" -eq 1 ]; then 367 | log_info "Importing AIOps Insights GPG key" 368 | if ! download_to_stdout "$gpg_uri" | apt-key add - > /dev/null; then 369 | log_error "AIOps Insights GPG key import failed" 370 | exit 1 371 | fi 372 | else 373 | AUTHENTICATION_PARAM='--allow-unauthenticated -o Acquire::AllowInsecureRepositories=true' 374 | fi 375 | 376 | log_info "Updating apt metadata" 377 | 378 | if ! apt-get ${AUTHENTICATION_PARAM} update -o Dir::Etc::sourcelist="sources.list.d/instana-agent.list" -o Dir::Etc::sourceparts="-" -o APT::Get::List-Cleanup="0" > /dev/null; then 379 | log_error "APT repository metadata update failed" 380 | exit 1 381 | fi 382 | 383 | log_info "Installing AIOps Insights agent" 384 | 385 | if ! apt-get ${AUTHENTICATION_PARAM} install -y instana-agent-${AGENT_TYPE} > /dev/null; then 386 | log_error "AIOps Insights agent package install failed" 387 | exit 1 388 | fi 389 | 390 | use_internal_packages 391 | ;; 392 | 393 | 'dnf') 394 | 395 | log_info "Setting up AIOps Insights RPM repository" 396 | 397 | local yum_repo 398 | read -r -d '' yum_repo < /etc/yum.repos.d/Instana-Agent.repo; then 410 | log_error "AIOps Insights YUM repository setup failed" 411 | exit 1 412 | fi 413 | 414 | log_info "Updating YUM metadata" 415 | if ! dnf makecache -y > /dev/null 2>&1; then 416 | log_error "YUM repository metadata update failed" 417 | exit 1 418 | fi 419 | 420 | log_info "Installing AIOps Insights agent" 421 | 422 | if ! dnf install -y instana-agent-$AGENT_TYPE > /dev/null; then 423 | log_error "AIOps Insights agent package install failed" 424 | exit 1 425 | fi 426 | 427 | use_internal_packages 428 | ;; 429 | 430 | 'yum') 431 | 432 | log_info "Setting up AIOps Insights YUM repository" 433 | 434 | local yum_repo 435 | read -r -d '' yum_repo < /etc/yum.repos.d/Instana-Agent.repo; then 447 | log_error "AIOps Insights YUM repository setup failed" 448 | exit 1 449 | fi 450 | 451 | log_info "Updating YUM metadata" 452 | if ! yum makecache -y fast > /dev/null 2>&1; then 453 | log_error "YUM repository metadata update failed" 454 | exit 1 455 | fi 456 | 457 | log_info "Installing AIOps Insights agent" 458 | 459 | if ! yum install -y instana-agent-$AGENT_TYPE > /dev/null; then 460 | log_error "AIOps Insights agent package install failed" 461 | exit 1 462 | fi 463 | 464 | use_internal_packages 465 | ;; 466 | 467 | 'zypper') 468 | 469 | log_info "Setting up AIOps Insights zypper repository" 470 | 471 | local zypp_repo 472 | read -r -d '' zypp_repo < /etc/zypp/repos.d/Instana-Agent.repo; then 484 | log_error "AIOps Insights zypper repository setup failed" 485 | exit 1 486 | fi 487 | 488 | if [ "${gpg_check}" -eq 1 ]; then 489 | log_info "Importing AIOps Insights GPG key" 490 | if ! rpm --import "$gpg_uri"; then 491 | log_error "AIOps Insights GPG key import failed" 492 | exit 1 493 | fi 494 | fi 495 | 496 | log_info "Updating zypper metadata" 497 | if ! zypper -n refresh Instana > /dev/null 2>&1; then 498 | log_error "zypper repository metadata update failed" 499 | exit 1 500 | fi 501 | 502 | log_info "Installing AIOps Insights agent" 503 | 504 | if ! zypper -n install instana-agent-$AGENT_TYPE > /dev/null; then 505 | log_error "AIOps Insights agent package install failed" 506 | exit 1 507 | fi 508 | 509 | use_internal_packages 510 | ;; 511 | 512 | *) 513 | log_error 'Unsupported package manager. The supported packages managers are: apt, dnf, yum, zypper' 514 | exit 1; 515 | 516 | esac 517 | 518 | } 519 | 520 | function configure_mode() { 521 | if [ "${MODE}" = 'apm' ]; then 522 | /bin/cp "${AGENT_DIR}/etc/instana/com.instana.agent.main.config.Agent.cfg.template" "${AGENT_DIR}/etc/instana/com.instana.agent.main.config.Agent.cfg" 523 | echo "mode = APM" >> "${AGENT_DIR}/etc/instana/com.instana.agent.main.config.Agent.cfg" 524 | 525 | return 0 526 | fi 527 | 528 | if [ "${MODE}" = 'aws' ]; then 529 | log_info 'Configuring AWS mode' 530 | # Get region from metadata endpoint 531 | 532 | if [ -n "${INSTANA_AWS_REGION_CONFIG}" ]; then 533 | log_info "Using the AWS region ${INSTANA_AWS_REGION_CONFIG} configured via the 'INSTANA_AWS_REGION_CONFIG' environment variable" 534 | export INSTANA_AWS_REGION_CONFIG 535 | elif ! INSTANA_AWS_REGION_CONFIG=$(download_to_stdout http://169.254.169.254/latest/dynamic/instance-identity/document | awk -F\" '/region/ {print $4}'); then 536 | log_error "Error querying AWS metadata. It seems this virtual machine is not running on EC2. Please set the 'INSTANA_AWS_REGION_CONFIG' environment variable manually." 537 | exit 1 538 | fi 539 | 540 | ROLES_FOUND=false 541 | 542 | if download_to_stdout http://169.254.169.254/latest/meta-data/iam/security-credentials/ > /dev/null 2>&1; then 543 | ROLES_FOUND=true 544 | fi 545 | 546 | if [ "$ROLES_FOUND" = "false" ]; then 547 | if [ -z "$AWS_ACCESS_KEY_ID" ] || [ -z "$AWS_SECRET_ACCESS_KEY" ]; then 548 | log_error "AWS_ACCESS_KEY_ID and/or AWS_SECRET_ACCESS_KEY not exported, and no IAM instance role detected to allow AWS API access." 549 | exit 1 550 | fi 551 | fi 552 | 553 | /bin/cp "${AGENT_DIR}/etc/instana/com.instana.agent.main.config.Agent.cfg.template" "${AGENT_DIR}/etc/instana/com.instana.agent.main.config.Agent.cfg" 554 | echo "mode = INFRASTRUCTURE" >> "${AGENT_DIR}/etc/instana/com.instana.agent.main.config.Agent.cfg" 555 | 556 | return 0 557 | fi 558 | 559 | if [ "$MODE" = "infra" ]; then 560 | /bin/cp "${AGENT_DIR}/etc/instana/com.instana.agent.main.config.Agent.cfg.template" "${AGENT_DIR}/etc/instana/com.instana.agent.main.config.Agent.cfg" 561 | echo "mode = INFRASTRUCTURE" >> "${AGENT_DIR}/etc/instana/com.instana.agent.main.config.Agent.cfg" 562 | 563 | return 0 564 | fi 565 | } 566 | 567 | function delete_git_repo() { 568 | rm -rf "${AGENT_DIR}/etc/.git" 569 | } 570 | 571 | function check_preexisting_git_repository() { 572 | if [ -n "${GIT_REPO}" ] && [ -d "${AGENT_DIR}/etc/.git" ]; then 573 | log_warn "The Git options have been specified, but there is already a Git repository in '${AGENT_DIR}/etc/.git'. To continue, we need to remove the current Git repository." 574 | 575 | if [ $PROMPT = true ]; then 576 | if receive_confirmation 'Do you want to continue?'; then 577 | delete_git_repo 578 | fi 579 | else 580 | delete_git_repo 581 | fi 582 | fi 583 | } 584 | 585 | function configure_env() { 586 | local env_content="" 587 | local env_path="" 588 | 589 | if [ "$INIT" = "systemd" ]; then 590 | env_path=/opt/instana/agent/etc/systemd.env 591 | else 592 | if [ "$FAMILY" = "zypper" ] || [ "$FAMILY" = "yum" ]; then 593 | env_path=/etc/sysconfig/instana-agent 594 | fi 595 | 596 | if [ "$FAMILY" = "apt" ]; then 597 | env_path=/etc/default/instana-agent 598 | fi 599 | fi 600 | 601 | [[ -n "$INSTANA_AWS_REGION_CONFIG" ]] && env_content+="$(get_env_line INSTANA_AWS_REGION_CONFIG $INSTANA_AWS_REGION_CONFIG)\n" 602 | [[ -n "$AWS_ACCESS_KEY_ID" ]] && env_content+="$(get_env_line AWS_ACCESS_KEY_ID $AWS_ACCESS_KEY_ID)\n" 603 | [[ -n "$AWS_SECRET_ACCESS_KEY" ]] && env_content+="$(get_env_line AWS_SECRET_ACCESS_KEY "$AWS_SECRET_ACCESS_KEY")\n" 604 | [[ -n "$GIT_REPO" && -n "$GIT_BRANCH" ]] && env_content+="$(get_env_line INSTANA_GIT_REMOTE_REPOSITORY "$GIT_REPO")\n$(get_env_line INSTANA_GIT_REMOTE_BRANCH "$GIT_BRANCH")\n" 605 | 606 | if [ -n "$GIT_USERNAME" ]; then 607 | env_content+="$(get_env_line INSTANA_GIT_REMOTE_USERNAME "$GIT_USERNAME")\n" 608 | if [ -n "$GIT_PASSWORD" ]; then 609 | env_content+="$(get_env_line INSTANA_GIT_REMOTE_PASSWORD "$GIT_PASSWORD")\n" 610 | else 611 | env_content+="$(get_env_line INSTANA_GIT_REMOTE_PASSWORD "")\n" 612 | fi 613 | fi 614 | 615 | printf "$env_content" > "$env_path" 616 | } 617 | 618 | # Write the optional agent configuration to the file system 619 | function configure_integration() { 620 | local conf_path="/opt/instana/agent/etc/instana/configuration-integration.yaml" 621 | [[ -n "$AGENT_CONF_BASE64" ]] && echo $AGENT_CONF_BASE64 | base64 -d > $conf_path 622 | } 623 | 624 | function get_env_line() { 625 | local key=$1 626 | local val=$2 627 | 628 | if [ "$INIT" = "systemd" ]; then 629 | echo "${key}=${val}" 630 | else 631 | echo "export ${key}=${val}" 632 | fi 633 | } 634 | 635 | function update_custom_systemd_unit_file () { 636 | # file does not exists -> new installation indicator 637 | if [ "$INIT" = "systemd" ] && [ ! -e /lib/systemd/system/instana-agent.service ]; then 638 | mkdir -p /etc/systemd/system/instana-agent.service.d/ 639 | local systemd_custom_start_conf 640 | read -r -d '' systemd_custom_start_conf < /etc/systemd/system/instana-agent.service.d/agent-custom-start.conf; then 646 | log_warn "Failed to create '/etc/systemd/system/instana-agent.service.d/agent-custom-start.conf'" 647 | fi 648 | 649 | fi 650 | } 651 | 652 | function update_agent_max_mem_conf() { 653 | local conf_file="/etc/systemd/system/instana-agent.service.d/custom-environment.conf" 654 | if [ -e $conf_file ]; then 655 | sed -i 's/^#*Environment=AGENT_MAX_MEM=.*$/Environment=AGENT_MAX_MEM=1024m/' $conf_file 656 | else 657 | mkdir -p /etc/systemd/system/instana-agent.service.d/ 658 | read -r -d '' agent_max_mem_conf < $conf_file; then 663 | log_warn "Failed to create '/etc/systemd/system/instana-agent.service.d/agent-custom-start.conf'" 664 | fi 665 | fi 666 | } 667 | 668 | function start_agent() { 669 | if systemctl is-active instana-agent > /dev/null 2>&1; then 670 | log_warn "AIOps Insights agent service is active and agent is reinstalled. Service will be restarted" 671 | START=true 672 | fi 673 | 674 | if [ $START = false ]; then 675 | return 0 676 | fi 677 | 678 | if [ "$INIT" = "systemd" ]; then 679 | 680 | if grep -iq 'SUSE' /etc/*release 2>/dev/null; then 681 | # remove SysV file on SUSE linux before enabling the service 682 | if [ -f /etc/init.d/instana-agent ]; then 683 | rm -f /etc/init.d/instana-agent 684 | fi 685 | fi 686 | 687 | if ! systemctl enable instana-agent > /dev/null 2>&1; then 688 | log_error "AIOps Insights agent service enable on boot failed" 689 | exit 1 690 | else 691 | log_info "AIOps Insights agent enabled on boot" 692 | fi 693 | 694 | log_info "Starting AIOps Insights Agent" 695 | if ! systemctl restart instana-agent > /dev/null 2>&1; then 696 | log_error "AIOps Insights agent service start failed" 697 | exit 1 698 | else 699 | log_info "AIOps Insights agent service started up" 700 | fi 701 | else 702 | log_warn "AIOps Insights agent automatic enable/startup by this script is only supported for systemd" 703 | log_warn "Utilize your distribution's init system methods to enable/start the agent" 704 | fi 705 | } 706 | 707 | while getopts "syjinl:e:t:m:a:d:i:g:b:u:p:c:" opt; do 708 | case $opt in 709 | a) 710 | INSTANA_AGENT_KEY=$OPTARG 711 | ;; 712 | b) 713 | GIT_BRANCH=$OPTARG 714 | ;; 715 | c) 716 | AGENT_CONF_BASE64=$OPTARG 717 | ;; 718 | l) 719 | LOCATION=$OPTARG 720 | ;; 721 | d) 722 | INSTANA_DOWNLOAD_KEY=$OPTARG 723 | ;; 724 | e) 725 | ENDPOINT=$OPTARG 726 | ;; 727 | g) 728 | GIT_REPO=$OPTARG 729 | ;; 730 | m) 731 | MODE=$OPTARG 732 | ;; 733 | n) 734 | INSTANA_AGENT_SYSTEMD_TYPE=notify 735 | ;; 736 | p) 737 | GIT_PASSWORD=$OPTARG 738 | ;; 739 | u) 740 | GIT_USERNAME=$OPTARG 741 | ;; 742 | s) 743 | START=true 744 | ;; 745 | i) 746 | USE_INTERNAL_PACKAGES=true 747 | ;; 748 | j) 749 | OPEN_J9="true" 750 | ;; 751 | t) 752 | AGENT_TYPE=$OPTARG 753 | # full and minimal are deprecated 754 | # remove this when the packages are removed 755 | if [ "$AGENT_TYPE" = "full" ]; then 756 | AGENT_TYPE=dynamic 757 | fi 758 | 759 | if [ "$AGENT_TYPE" = "minimal" ]; then 760 | AGENT_TYPE=dynamic 761 | fi 762 | ;; 763 | y) 764 | PROMPT=false 765 | ;; 766 | \?) 767 | echo "Invalid option: -$OPTARG" >&2 768 | exit 1 769 | ;; 770 | esac 771 | done 772 | 773 | if [ "$(id -u)" != "0" ]; then 774 | log_error "This script must be executed as a user with root privileges" 775 | exit 1 776 | fi 777 | 778 | if [ "$OS" = "Darwin" ]; then 779 | log_error "Agent install script does not support macOS. Please download the macOS package from the 'Installing AIOps Insights Agents' wizard." 780 | exit 1 781 | fi 782 | 783 | if [ "$OS" = "AIX" ]; then 784 | log_error "Agent install script does not support AIX. Please download the AIX package from the 'Installing AIOps Insights Agents' wizard." 785 | exit 1 786 | fi 787 | 788 | if [ "$OS" = "SunOS" ]; then 789 | log_error "Agent install script does not support Solaris. Please download the Solaris package from the 'Installing AIOps Insights Agents' wizard." 790 | exit 1 791 | fi 792 | 793 | detect_machine 794 | 795 | if [ $MACHINE != "x86_64" ] && [ $MACHINE != "aarch64" ] && [ $MACHINE != "s390x" ] && [ $MACHINE != "ppc64le" ]; then 796 | log_error "Systems architecture: $MACHINE not supported" 797 | exit 1 798 | fi 799 | 800 | if [ ! "$INSTANA_AGENT_KEY" ]; then 801 | echo "-a INSTANA_AGENT_KEY required!" 802 | exit 1 803 | fi 804 | 805 | if [ ! "$INSTANA_DOWNLOAD_KEY" ]; then 806 | INSTANA_DOWNLOAD_KEY="$INSTANA_AGENT_KEY" 807 | fi 808 | 809 | if [ $AGENT_TYPE != "static" ] && [ $AGENT_TYPE != "dynamic" ]; then 810 | log_error "Invalid agent type specified $AGENT_TYPE" 811 | exit 1 812 | fi 813 | 814 | if [ "$ENDPOINT" != "" ]; then 815 | if ! echo "$ENDPOINT" | grep ":" &>/dev/null; then 816 | log_error "Agent endpoint must be in the format of :" 817 | exit 1 818 | fi 819 | fi 820 | 821 | if [ -n "${LOCATION}" ]; then 822 | log_warn "The -l parameter is deprecated and will not be updated to cover new SaaS regions going forward. Use -e instead." 823 | if [ "${LOCATION}" != "eu" ] && [ "${LOCATION}" != "us" ] && [ "${LOCATION}" != "red" ] && [ "${LOCATION}" != "blue" ] && [ "${LOCATION}" != "green" ]; then 824 | log_error "Invalid location '${LOCATION}' specified. Please select 'blue', 'red' or 'green'." 825 | exit 1 826 | fi 827 | fi 828 | 829 | if [ "$MODE" != "apm" ] && [ "$MODE" != "aws" ] && [ "$MODE" != "infra" ]; then 830 | log_error "Invalid mode specified. Supported modes: apm | aws | infra." 831 | exit 1 832 | fi 833 | 834 | if [ $OPEN_J9 = "false" ]; then 835 | if [ $MACHINE = "s390x" ] || [ $MACHINE = "ppc64le" ]; then 836 | log_info "For the '${MACHINE}' architecture only OpenJ9 JDK is available. Enforcing OpenJ9 agent runtime." 837 | OPEN_J9="true" 838 | fi 839 | fi 840 | 841 | if [ $OPEN_J9 = "true" ]; then 842 | AGENT_TYPE="${AGENT_TYPE}-j9" 843 | fi 844 | 845 | if [ ! "$INSTANA_DOWNLOAD_KEY" ]; then 846 | INSTANA_DOWNLOAD_KEY="$INSTANA_AGENT_KEY" 847 | fi 848 | 849 | if [ -n "${GIT_REPO}" ]; then 850 | if [ -z "${GIT_BRANCH}" ]; then 851 | log_error "The '-g' option for the Git repository has been specified without the '-b' option to specify the remote branch." 852 | exit 1 853 | fi 854 | else 855 | if [ -n "${GIT_BRANCH}" ]; then 856 | log_error "The '-b' option for the remote branch has been specified without the '-g' option to specify the Git repository." 857 | exit 1 858 | fi 859 | 860 | if [ -n "${GIT_USERNAME}" ]; then 861 | log_error "The '-u' option for the username to authenticate with has been specified without the '-g' option to specify the Git repository." 862 | exit 1 863 | fi 864 | 865 | if [ -n "${GIT_PASSWORD}" ]; then 866 | log_error "The '-p' option for the password to authenticate with has been specified without the '-g' option to specify the Git repository." 867 | exit 1 868 | fi 869 | fi 870 | 871 | if [ -n "${GIT_PASSWORD}" ]; then 872 | if [ -z "${GIT_USERNAME}" ]; then 873 | log_error "The '-p' option for the password to authenticate with has been specified without the '-u' option to specify the username." 874 | exit 1 875 | fi 876 | fi 877 | 878 | detect_family 879 | 880 | detect_init 881 | 882 | echo "Setting up the ${AGENT_TYPE} AIOps Insights agent for $OS" 883 | 884 | if [ $PROMPT = false ]; then 885 | response=y 886 | else 887 | check_existing_agent 888 | if ! receive_confirmation "Are you sure?"; then 889 | exit 1 890 | fi 891 | fi 892 | 893 | check_prerequisites 894 | 895 | export INSTANA_AGENT_KEY 896 | export INSTANA_DOWNLOAD_KEY 897 | export INSTANA_AGENT_HOST 898 | export INSTANA_AGENT_PORT 899 | export INSTANA_PRODUCT_NAME 900 | 901 | check_download_key 902 | 903 | get_endpoint 904 | 905 | 906 | update_custom_systemd_unit_file 907 | 908 | if ! setup_agent; then 909 | exit 1 910 | fi 911 | 912 | configure_mode 913 | 914 | check_preexisting_git_repository 915 | 916 | configure_env 917 | 918 | configure_integration 919 | 920 | update_agent_max_mem_conf 921 | 922 | if ! start_agent; then 923 | exit 1 924 | fi 925 | --------------------------------------------------------------------------------