1+ #! /usr/bin/env bash
2+ set -euo pipefail
3+
4+ LOG_FILE=" install-tools.log"
5+ SUMMARY_FILE=" ${SUMMARY_FILE:- install-summary.json} "
6+ VERSIONS_FILE=" ${VERSIONS_FILE:- .devcontainer/ .tool-versions.json} "
7+ DRY_RUN=false
8+ INSTALL_TOOLS=(all)
9+
10+ for arg in " $@ " ; do
11+ case $arg in
12+ --dry-run)
13+ DRY_RUN=true
14+ echo " [Dry Run] No changes will be made. Commands will be printed only."
15+ ;;
16+ --tools=* )
17+ IFS=' ,' read -ra INSTALL_TOOLS <<< " ${arg#*=}"
18+ ;;
19+ --summary-path=* )
20+ SUMMARY_FILE=" ${arg#* =} "
21+ ;;
22+ esac
23+ done
24+
25+ exec > >( tee -a " $LOG_FILE " ) 2>&1
26+
27+ RED=' \033[0;31m'
28+ GREEN=' \033[0;32m'
29+ YELLOW=' \033[1;33m'
30+ NC=' \033[0m'
31+
32+ SUMMARY_JSON=" {}"
33+ EXPECTED_JSON=" {}"
34+
35+ if [[ -f " $VERSIONS_FILE " ]]; then
36+ EXPECTED_JSON=$( < " $VERSIONS_FILE " )
37+ fi
38+
39+ log_step () {
40+ echo -e " \n${YELLOW} 🔧 $( date ' +%Y-%m-%d %H:%M:%S' ) - $1 ${NC} "
41+ }
42+
43+ run_cmd () {
44+ log_step " $1 "
45+ shift
46+ if $DRY_RUN ; then
47+ echo " [Dry Run] $* "
48+ else
49+ if " $@ " ; then
50+ echo -e " ${GREEN} ✅ Success: $1 ${NC} "
51+ else
52+ echo -e " ${RED} ❌ Failed: $1 ${NC} "
53+ exit 1
54+ fi
55+ fi
56+ }
57+
58+ add_summary () {
59+ local name=$1
60+ local version=$2
61+ SUMMARY_JSON=$( echo " $SUMMARY_JSON " | jq --arg name " $name " --arg ver " $version " ' . + {($name): $ver}' )
62+
63+ local expected_version
64+ expected_version=$( echo " $EXPECTED_JSON " | jq -r --arg name " $name " ' .[$name] // empty' )
65+
66+ if [[ -n " $expected_version " && " $version " != " $expected_version " ]]; then
67+ echo -e " ${RED} ⚠️ Version mismatch for $name : expected $expected_version , got $version ${NC} "
68+ fi
69+ }
70+
71+ get_expected_version () {
72+ local name=$1
73+ echo " $EXPECTED_JSON " | jq -r --arg name " $name " ' .[$name] // empty'
74+ }
75+
76+ should_run () {
77+ [[ " ${INSTALL_TOOLS[*]} " =~ " all " || " ${INSTALL_TOOLS[*]} " =~ " $1 " ]]
78+ }
79+
80+ # OS dependencies
81+ log_step " Installing OS dependencies"
82+ run_cmd " Install OS dependencies" sudo apt-get update -y && sudo apt-get install -y \
83+ curl unzip git jq gnupg software-properties-common ca-certificates lsb-release tar build-essential apt-transport-https
84+
85+ # Terraform (manual installation)
86+ if should_run terraform; then
87+ log_step " Installing Terraform"
88+ version=$( get_expected_version terraform)
89+ version=" ${version:- 1.8.4} "
90+
91+ if ! $DRY_RUN ; then
92+ run_cmd " Download Terraform" curl -sLo terraform.zip " https://releases.hashicorp.com/terraform/${version} /terraform_${version} _linux_amd64.zip"
93+ run_cmd " Unzip Terraform" unzip -o terraform.zip
94+ run_cmd " Move Terraform" sudo mv terraform /usr/local/bin/
95+ rm -f terraform.zip
96+ fi
97+
98+ TERRAFORM_VERSION=$( terraform version -json | jq -r .terraform_version)
99+ add_summary terraform " $TERRAFORM_VERSION "
100+ fi
101+
102+ # AWS CLI
103+ if should_run awscli; then
104+ log_step " Installing AWS CLI"
105+ run_cmd " Download AWS CLI" curl " https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o " awscliv2.zip"
106+ run_cmd " Unzip AWS CLI" unzip -o awscliv2.zip
107+ run_cmd " Install AWS CLI" sudo ./aws/install --update
108+ rm -rf awscliv2.zip aws
109+ AWS_VERSION=$( aws --version 2>&1 | awk ' {print $1}' | cut -d/ -f2)
110+ add_summary awscli " $AWS_VERSION "
111+ fi
112+
113+ # Ansible
114+ if should_run ansible; then
115+ log_step " Installing Ansible"
116+ version=$( get_expected_version ansible)
117+
118+ if ! $DRY_RUN ; then
119+ run_cmd " Update apt" sudo apt-get update -y
120+ run_cmd " Install Python pip" sudo apt-get install -y python3-pip
121+ if [[ -n " $version " && " $version " != " latest" ]]; then
122+ run_cmd " Install Ansible" sudo pip3 install --break-system-packages " ansible==${version} "
123+ else
124+ run_cmd " Install Ansible" sudo pip3 install --break-system-packages ansible
125+ fi
126+ fi
127+
128+ ANSIBLE_VERSION=$( ansible --version 2> /dev/null | head -n1 | awk ' {print $2}' | tr -d ' []' || echo " installed" )
129+ add_summary ansible " $ANSIBLE_VERSION "
130+ fi
131+
132+ # Node.js
133+ if should_run nodejs; then
134+ log_step " Installing Node.js"
135+
136+ if ! $DRY_RUN ; then
137+ # Check if nodejs is already installed from base image
138+ if command -v node & > /dev/null; then
139+ log_step " Node.js already installed, ensuring npm is available"
140+ # Install npm separately if nodejs exists but npm doesn't
141+ if ! command -v npm & > /dev/null; then
142+ run_cmd " Install npm" sudo apt-get update && sudo apt-get install -y npm
143+ fi
144+ else
145+ # Fresh installation from NodeSource
146+ version=$( get_expected_version nodejs)
147+ version=" ${version:- 20} "
148+ run_cmd " Download NodeSource setup script" curl -fsSL https://deb.nodesource.com/setup_${version} .x -o nodesource_setup.sh
149+ run_cmd " Run NodeSource setup" sudo -E bash nodesource_setup.sh
150+ run_cmd " Install Node.js and npm" sudo apt-get install -y nodejs
151+ rm -f nodesource_setup.sh
152+ fi
153+ fi
154+
155+ NODE_VERSION=$( node -v 2> /dev/null | sed ' s/v//' )
156+ NPM_VERSION=$( npm -v 2> /dev/null || echo " not installed" )
157+ add_summary nodejs " $NODE_VERSION "
158+ add_summary npm " $NPM_VERSION "
159+ fi
160+
161+ # http-server (npm package)
162+ if should_run http-server; then
163+ log_step " Installing http-server"
164+ run_cmd " Install http-server globally" sudo npm install -g http-server
165+ HTTPSERVER_VERSION=$( http-server --version 2> /dev/null || echo " installed" )
166+ add_summary http-server " $HTTPSERVER_VERSION "
167+ fi
168+
169+ # Google Cloud SDK
170+ if should_run gcloud; then
171+ log_step " Installing Google Cloud SDK"
172+
173+ if ! $DRY_RUN ; then
174+ log_step " Add gcloud apt key"
175+ curl -fsSL https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo gpg --yes --dearmor -o /usr/share/keyrings/cloud.google.gpg
176+ echo -e " ${GREEN} ✅ Success: Add gcloud apt key${NC} "
177+ log_step " Add gcloud repository"
178+ echo " deb [signed-by=/usr/share/keyrings/cloud.google.gpg] https://packages.cloud.google.com/apt cloud-sdk main" | sudo tee /etc/apt/sources.list.d/google-cloud-sdk.list > /dev/null
179+ echo -e " ${GREEN} ✅ Success: Add gcloud repository${NC} "
180+ run_cmd " Update apt" sudo apt-get update -y
181+ run_cmd " Install gcloud" sudo apt-get install -y google-cloud-cli
182+ fi
183+
184+ GCLOUD_VERSION=$( gcloud version --format=" value(version)" 2> /dev/null || echo " installed" )
185+ add_summary gcloud " $GCLOUD_VERSION "
186+ fi
187+
188+ # Azure CLI
189+ if should_run azurecli; then
190+ log_step " Installing Azure CLI"
191+
192+ if ! $DRY_RUN ; then
193+ run_cmd " Install Azure CLI dependencies" sudo apt-get update && sudo apt-get install -y ca-certificates curl apt-transport-https lsb-release gnupg
194+ log_step " Download Microsoft signing key"
195+ curl -fsSL https://packages.microsoft.com/keys/microsoft.asc | sudo gpg --yes --dearmor -o /etc/apt/keyrings/microsoft.gpg
196+ echo -e " ${GREEN} ✅ Success: Download Microsoft signing key${NC} "
197+ run_cmd " Set key permissions" sudo chmod go+r /etc/apt/keyrings/microsoft.gpg
198+ log_step " Add Azure CLI repository"
199+ echo " deb [arch=$( dpkg --print-architecture) signed-by=/etc/apt/keyrings/microsoft.gpg] https://packages.microsoft.com/repos/azure-cli/ $( lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/azure-cli.list > /dev/null
200+ echo -e " ${GREEN} ✅ Success: Add Azure CLI repository${NC} "
201+ run_cmd " Update apt" sudo apt-get update -y
202+ run_cmd " Install Azure CLI" sudo apt-get install -y azure-cli
203+ fi
204+
205+ AZCLI_VERSION=$( az version --output json 2> /dev/null | jq -r ' ."azure-cli"' || echo " installed" )
206+ add_summary azurecli " $AZCLI_VERSION "
207+ fi
208+
209+ # Write summary
210+ if ! $DRY_RUN ; then
211+ echo " $SUMMARY_JSON " | jq . > " $SUMMARY_FILE "
212+ echo -e " \n${GREEN} 📦 Tool summary written to $SUMMARY_FILE ${NC} "
213+ fi
214+
215+ echo -e " \n${GREEN} ✅ All tools installed successfully at $( date ' +%Y-%m-%d %H:%M:%S' ) ${NC} "
0 commit comments