#!/usr/bin/env bash ### Configuration ## Enable extended globbing features shopt -s extglob # Parent directory M_PREFIX=${M_PREFIX-$HOME/.local} # Top level directory for files managed by `m` M_DIR=$M_PREFIX/m # Directory to symlink binaries into M_BIN_DIR=${M_BIN_DIR-$M_PREFIX/bin} # Directory for MongoDB version binaries VERSIONS_DIR=$M_DIR/versions # Directory for MongoDB Tools version binaries TOOLS_DIR=$M_DIR/tools/versions # Working directory for unpacking MongoDB tarballs BUILD_DIR_BASE=$M_DIR/mongo- ### Dev/test/experimental settings DEBUG=${M_DEBUG:-0} # Use cache? CACHE=${M_CACHE:-0} # Confirm before downloading? CONFIRM=${M_CONFIRM:-1} # Location of cached source file CACHE_SRC=${M_CACHE_SRC:-$M_DIR/cache-src.json} # Cache source expiry (seconds) CACHE_EXPIRY=${M_CACHE_EXPIRY:-3600} # m version VERSION="1.9.0" # # Log the given # log() { printf "... $@\n" } # # Log the given if in debug mode # debug() { if [[ "$DEBUG" == 1 ]]; then printf "$@\n" 1>&2 fi } # # Exit with the given # abort() { printf "Error: $@\n" && exit 1 } # # Exit with advice for version that isn't available # abort_not_installed() { local version=$1 printf "Error: requested MongoDB version is not installed\n" if [[ ! -z "$version" ]]; then printf "Try 'm $version' to download and activate.\n" fi exit 1 } # # Check file age (in seconds) # file_age_in_seconds() { local FILE_TIME=`date -r "$1" +%s`; local TIME_NOW=`date +%s`; echo "$[ ${TIME_NOW} - ${FILE_TIME} ]"; } ### Setup test -d $VERSIONS_DIR || mkdir -p $VERSIONS_DIR if ! test -d $VERSIONS_DIR; then abort "Failed to create versions directory ($VERSIONS_DIR), do you have permissions to do this?" fi # curl / wget support GET= # wget support (Added --no-check-certificate for Github downloads) which wget >/dev/null 2>&1 && GET="wget -q -O-" # curl support which curl >/dev/null 2>&1 && GET="curl -s -L" # Ensure we have curl or wget test -z "$GET" && abort "curl or wget required" # # Output usage information. # display_help() { cat <<-help m v$VERSION (MongoDB Version Management) Usage: m [options] [COMMAND] [config] Commands: m Output versions installed m stable [config ...] Install or activate the latest stable MongoDB release m latest [config ...] Install or activate the latest MongoDB release (including dev & RCs) m X.Y Install or activate the latest patch release for MongoDB X.Y (eg. 7.0) m [config ...] Install and/or use MongoDB m reinstall Remove and reinstall MongoDB m --legacy Install generic Linux version (does not include SSL) m use [args ...] Execute mongod with [args ...] m shard [args ...] Execute mongos with [args ...] m shell [args ...] Open a mongo shell with [args ...] m bin Output bin path for m rm Remove the given version(s) m --stable Output the latest stable MongoDB version available m --stable X.Y .. for release series X.Y (eg. 7.0) m --latest Output the latest MongoDB version available (including dev & RCs) m --latest X.Y .. for release series X.Y (eg. 7.0) m ls Output the versions of MongoDB available m installed [--json] Output installed versions available (optionally, in JSON format) m src Output the url for source used for the given (useful if installed from source) m pre [script] Declare one or list scripts to execute before (scripts must use absolute paths) m post [script] Declare one or list scripts to execute after (scripts must use absolute paths) m pre rm [script] Remove pre script m post rm [script] Remove post script m tools stable Install or activate the latest stable Database Tools release m tools X.Y.Z Install or activate the Database Tools X.Y.Z m tools ls Output the versions of the Database Tools available m tools installed [--json] Output installed versions of the Database Tools available Events: change Occurs when switching MongoDB versions install Occurs when installing a previously uninstalled MongoDB version Options: -V, --version Output current version of m -h, --help Display help information Aliases: installed lls shard sd, mongos shell s, sh, mongo list ls, available, avail use as, mongod which bin help exit 0 } # # Output m version. # display_m_version() { debug "$0" echo $VERSION && exit 0 } # # Internal helper to get all versions # get_all_versions() { local src_url="https://downloads.mongodb.org/full.json" if [ $CACHE == 1 ]; then # Use the cached versions if valid if [ -e $CACHE_SRC ]; then debug "$CACHE_SRC is $(file_age_in_seconds $CACHE_SRC) seconds old (expiry: $CACHE_EXPIRY)" if [ $(file_age_in_seconds $CACHE_SRC) -lt $CACHE_EXPIRY ]; then debug "Using cache: $CACHE_SRC" all_versions=`cat $CACHE_SRC` fi fi fi if [ -z "$all_versions" ]; then debug "get_all_versions(): $GET $src_url" all_versions=`$GET 2> /dev/null $src_url` if [ $CACHE ]; then debug "Creating cache: $CACHE_SRC" echo "$all_versions" > $CACHE_SRC fi fi } # # Check for installed version, and populate $active # check_current_version() { which mongo &> /dev/null if test $? -eq 0; then active=`mongod --version | grep "version\s*v[0-9]" | grep -E -o '[0-9]+\.[0-9]+\.[0-9]+([-_\.][a-zA-Z0-9]+)?' | head -1` ent=`mongod --version | grep -E "(modules:\s*)|\"enterprise\"?" | wc -l` if [[ $ent == *1 ]]; then active="$active-ent" fi fi } # # Display current MongoDB --version # and others installed. # display_versions() { local option=$1; shift local json=false declare -a versions versions=(`ls -1 $VERSIONS_DIR | sort -t. -k 1,1n -k 2,2n -k 3,3n`) if test -z "$versions"; then echo No installed versions return fi local last=${versions[${#versions[@]}-1]} if test "$option" = "--json"; then json=true printf "[" fi check_current_version for version in ${versions[@]}; do local dir="$VERSIONS_DIR/$version" local config=`test -f "$dir"/.config && cat "$dir"/.config` if $json; then printf "\n {\n \"name\" : \"$version\",\n \"path\" : \"$dir/bin/\" \n }" if [ "$version" != "$last" ]; then printf "," fi else if [ "$version" = "$active" ]; then printf " * $version $config\n" else printf " $version $config\n" fi fi done if $json; then printf "\n]\n" fi } # # Install and activate MongoDB Database Tools. # Will install the full server for version <4.3.2 since the tools # are included with the server for those versions. # # install_tools # install_tools() { local version=$1 check_current_tools_version check_current_version if [[ $version == $active_tools ]]; then printf "Already Active: MongoDB Server $active, MongoDB Database Tools $active_tools\n" exit 0 fi if [[ $version =~ "rc" ]]; then local rc="--rc" fi get_all_tools_versions $rc if [[ $version == "stable" ]]; then # Set version to the latest available version version=`echo $versions | awk 'NF>1{print $NF}'` fi version_test=`echo $version | sed 's/-ent$//'` if [[ ! $versions =~ $version_test ]]; then printf "Could not find any releases for the requested version "$version" of Database Tools\n" exit 1; fi if verlt $version "99.0.0"; then # Tools are included in the server for $version local dir=$VERSIONS_DIR/$version if test ! -d $dir; then prompt_install "Database Tools version $version is not installed." install_bin $version fi printf "\nActivating: MongoDB Server $active, MongoDB Database Tools $version\n" debug "DB Tools path: $dir" ln -fs $dir/bin/bsondump \ $dir/bin/mongodump \ $dir/bin/mongorestore \ $dir/bin/mongoimport \ $dir/bin/mongoexport \ $dir/bin/mongofiles \ $dir/bin/mongostat \ $dir/bin/mongotop \ $dir/bin/mongoreplay \ $dir/bin/mongooplog \ $dir/bin/mongosniff \ $dir/bin/mongoperf \ $M_BIN_DIR else # Separately released tools local dir=$TOOLS_DIR/$version if test ! -d $dir; then prompt_install "Database Tools version $version is not installed." install_tools_bin $version fi printf "\nActivating: MongoDB Server $active, MongoDB Database Tools $version\n" debug "DB Tools path: $dir" ln -fs $dir/bin/* $M_BIN_DIR fi } # # Install MongoDB Database Tools binaries for provided version # # install_tools_bin # install_tools_bin() { local version=$1 community=1 log "installing binary" ext="tgz" get_distro_and_arch if [[ $os = "linux" ]]; then # for linux fetch the rhel7 tarball by default local dist=rhel70 # shadowing earlier $distro for distro in $distros; do if good "https://fastdl.mongodb.org/tools/db/mongodb-database-tools-$distro-$arch-$version.tgz"; then dist=$distro break fi done fi if [[ $os = "osx" ]]; then dist="macos" if vergte $version "100.1.0"; then ext="zip" fi if [[ "$arch" = "arm64" ]]; then if verlte "$version" "100.7.0"; then echo "" echo "NOTE: Apple Silicon is not natively supported for this version of MongoDB Database Tools" echo " ==> Changing detected architecture from arm64 to x86_64 so Rosetta 2 can be used" echo " More info: https://support.apple.com/en-au/HT211861" echo "" arch="x86_64" fi fi fi printf "Downloading from https://fastdl.mongodb.org/tools/db/mongodb-database-tools-$dist-$arch-$version.$ext" $GET https://fastdl.mongodb.org/tools/db/mongodb-database-tools-$dist-$arch-$version.$ext -o $M_DIR/tools-$version.$ext if test $? -gt 0; then printf "Error: tools installation failed\n" printf " Tarball fetch for MongoDB tools version $version failed.\n" printf " Try a different version or view $logpath to view\n" printf " error details.\n" exit 1 fi mkdir -p $TOOLS_DIR/$version if [[ $ext = "zip" ]]; then unzip -q $M_DIR/tools-$version.zip -d $TOOLS_DIR/$version else tar -xzf $M_DIR/tools-$version.tgz -C $TOOLS_DIR/$version fi mv $TOOLS_DIR/$version/mongodb-database-tools-$dist-$arch-$version/* $TOOLS_DIR/$version rm -r $TOOLS_DIR/$version/mongodb-database-tools-$dist-$arch-$version log "removing source" rm $M_DIR/tools-$version.$ext log "Installation complete" } # # Find the current installed version of tools. # check_current_tools_version() { which mongodump &> /dev/null if test $? -eq 0; then # Note: this regex only works for mongodump 3.0+ active_tools=`mongodump --version | sed -nE "s/mongodump version\: r?(.*)$/\1/p"` fi } # # Find all available versions of the database tools. # Includes server versions up to 4.3.1. # get_all_tools_versions() { local tools_regex="([0-3]\.[0-9]+\.[0-9]+|4\.[0-2]\.[0-9]+|4\.3\.[01])" local rc_regex="" local all_versions="" if [[ $1 == "--rc" ]]; then local rc_regex="(-rc[0-9]+)?" fi tools_versions=`curl -s \ -H "Accept: application/vnd.github.v3+json" \ https://api.github.com/repos/mongodb/mongo-tools/git/refs/tags \ | sed -nE "s/^.*\"ref\"\: \"refs\/tags\/r?([[:digit:]]{2,3}\.[[:digit:]]+\.[[:digit:]]+)\",$/\1/p" \ | sort -V` get_all_versions server_versions=`echo $all_versions \ | grep -E -o "$tools_regex$rc_regex" \ | sort -u \ | sort -s -k 2.3n -t - \ | sort -s -k 1,1n -k 2,2n -k 3,3n -t . \ | awk '{ if ($1 ) { print " " $1 } }'` versions="$server_versions $tools_versions" } # # Output all database tools versions # list_tools_versions() { check_current_tools_version if [[ $2 == "--rc" ]]; then local rc="--rc" fi get_all_tools_versions $rc for v in $versions; do if test "$active_tools" = "$v"; then printf " $v\n" else if test -d $VERSIONS_DIR/$v || test -d $TOOLS_DIR/$v; then printf " * $v\n" else printf " $v\n" fi fi done } # # Version less than or equal # verlte() { [ "$1" = "`echo -e "$1\n$2" | sort -V | head -n1`" ] } # # Version greater than or equal # vergte() { [ "$1" = "`echo -e "$1\n$2" | sort -rV | head -n1`" ] } # # Version less than # verlt() { [ "$1" = "$2" ] && return 1 || verlte $1 $2 } # # Output all installed tools versions. # Pass "--json" to output in JSON format. # display_tools_versions() { local option=$1; shift local json=false declare -a versions if [ -e $TOOLS_DIR ]; then versions=(`(ls -1 $VERSIONS_DIR; ls -1 $TOOLS_DIR) | sort -t. -k 1,1n -k 2,2n -k 3,3n`) fi if test -z "$versions"; then echo "No installed versions" return fi local last=${versions[${#versions[@]}-1]} if test "$option" = "--json"; then json=true printf "[" fi check_current_tools_version for version in ${versions[@]}; do num_version=$(numeric_version $version) if verlt $version "99.0.0" && vergte $version "4.3.2"; then continue fi local dir="$TOOLS_DIR/$version" local config=`test -f "$dir"/.config && cat "$dir"/.config` if $json; then printf "\n {\n \"name\" : \"$version\",\n \"path\" : \"$dir/bin/\" \n }" if [ "$version" != "$last" ]; then printf "," fi else if [ "$version" = "$active_tools" ]; then printf " $version $config\n" else printf " $version $config\n" fi fi done if $json; then printf "\n]\n" fi } # # Install MongoDB [config ...] # install_mongo() { local version=$1; shift local config=$@ local rc="" local flavour="stable" check_current_version check_current_tools_version # Default to stable releases, with option to include RCs if [[ ! -z "$config" ]]; then case "$config" in latest|--latest|rc|--rc) debug "Using --latest config (includes dev & RCs)" rc="([-_\.]rc[0-9]+)?" flavour="latest" config="" ;; legacy|--legacy) debug "Using generic Linux legacy config (does not include SSL)" _legacy_only=y config="" shift ;; esac fi if test "$version" = "$active"; then echo "Already Active: MongoDB Server $version, MongoDB Database Tools $active_tools" exit 0; fi debug "CURRENT: $version" # shorthand for finding latest in a release series (eg: "3.6", "3.6-ent") if [[ $version =~ ^([0-9])\.([0-9]+)(-ent)?$ ]]; then local series="${BASH_REMATCH[1]}\.${BASH_REMATCH[2]}" local ent="${BASH_REMATCH[3]}" local all_versions="" get_all_versions printf ">> Checking for $flavour release of MongoDB $version\n" if test "$flavour" = "latest"; then debug "grep -E -o \"$series\.[0-9]+$rc\"" version=`echo $all_versions \ | grep '"version\":' \ | grep -E -o "$series\.[0-9]+$rc" \ | sort -u -k 1,1n -k 2,2n -k 3,3n -t . \ | tail -n1` else debug "grep -E -v \"[-]rc\" | grep -E -o \"$series\.[0-9]+\" " version=`echo $all_versions \ | grep '"version\":' \ | grep -E -o "$series\.[0-9]+\.zip" \ | sed s/.zip$// \ | sort -u -k 1,1n -k 2,2n -k 3,3n -t . \ | tail -n1` fi version="$version$ent" fi debug "TARGET: $version" debug "FLAVOUR: $flavour" if [[ -z "$version" ]]; then abort "Could not find any releases for the requested version\n" fi local dir=$VERSIONS_DIR/$version if ! test -d $dir; then # install prompt_install "MongoDB version $version is not installed." install_bin $version $config fi tools_glob="bsondump|mongodump|mongorestore|mongoimport|mongoexport|mongofiles|mongostat|mongotop|mongoreplay|mongooplog|mongosniff|mongoperf" # activate pre change printf "\nActivating: MongoDB Server $version, MongoDB Database Tools $active_tools\n" debug "Symlinking binaries in $dir/bin to $M_BIN_DIR" mkdir -p "$M_BIN_DIR" cd $dir \ && ln -fs $dir/bin/!($tools_glob) $M_BIN_DIR \ && post change echo "" echo "Installation to $M_BIN_DIR complete!" if [[ $PATH != *"$M_BIN_DIR"* ]];then echo "" echo "==> WARNING: \$PATH does not include $M_BIN_DIR" fi echo "" if vergte $version "6.0.0"; then if ! command -v mongosh &> /dev/null; then echo "" echo "NOTE: the legacy mongo shell is not included in MongoDB 6.0+ distributions" echo "" echo "Download the new MongoDB Shell (mongosh):" echo " https://www.mongodb.com/try/download/shell" echo "" # Convenience for macOS users if [[ "$(uname)" == "Darwin" ]]; then if command -v brew &> /dev/null; then prompt_install "Install "mongosh" via brew?" `brew install mongosh` else echo "Install via brew:" echo " brew install mongosh" fi echo "" fi fi fi } # # Prompt installation # # prompt_install "About to install something" # prompt_install() { if [[ "$CONFIRM" == 1 ]]; then echo $1 while true; do read -p "Installation may take a while. Would you like to proceed? [y/N] " yn case $yn in [Yy]* ) break ;; * ) echo "Aborted."; exit ;; esac done fi } # # Convert version string to numeric for comparison # numeric_version () { echo "$1" | awk -F. '{ printf("%d%02d%02d\n", $1,$2,$3); }'; } # # Install MongoDB binary # # template http://fastdl.mongodb.org/$OS/mongodb-$OS-$ARCH-$VERSION.tgz # # linux32 http://fastdl.mongodb.org/linux/mongodb-linux-i686-2.2.2.tgz # linux64 http://fastdl.mongodb.org/linux/mongodb-linux-x86_64-2.2.2.tgz # osx64 http://fastdl.mongodb.org/osx/mongodb-osx-x86_64-2.2.2.tgz # osx64 ssl http://fastdl.mongodb.org/osx/mongodb-osx-ssl-x86_64-3.0.4.tgz # solaris64 http://fastdl.mongodb.org/sunos5/mongodb-sunos5-x86_64-2.2.2.tgz # # not supported # win32 http://fastdl.mongodb.org/win32/mongodb-win32-i386-2.3.2.zip # win64 http://fastdl.mongodb.org/win32/mongodb-win32-x86_64-2.0.8.zip # win64 2008+ http://fastdl.mongodb.org/win32/mongodb-win32-x86_64-2008plus-2.0.3.zip # install_bin() { local version=$1 local config=$2 community=1 # check if enterprise if [[ $version == *-ent ]]; then community=0 version=${version%????} fi if ! test -z $config; then # config was passed, must build from source debug "install_bin(): unsupported config ($config) passed" local tarball="mongodb-src-r$version.tar.gz" local url="http://downloads.mongodb.org/src/$tarball" install_tarball $version $url $config exit 0 fi # determine url based on os and arch get_distro_and_arch # determine the download url if [[ "$community" == 1 ]]; then local tarball="mongodb-$sslbuild-$arch-$version.tgz" # shadowing earlier $distro for distro in $distros; do if good "http://fastdl.mongodb.org/$os/mongodb-$sslbuild-$arch-$distro-$version.tgz"; then tarball="mongodb-$sslbuild-$arch-$distro-$version.tgz" break fi done local url="http://fastdl.mongodb.org/$os/$tarball" else # enterprise version case $os in linux* ) # for linux fetch the rhel7 tarball by default local dist=rhel70 # shadowing earlier $distro for distro in $distros; do if good "http://downloads.mongodb.com/$os/mongodb-$os-$arch-enterprise-$distro-$version.tgz"; then dist=$distro tarball="mongodb-$os-$arch-enterprise-$distro-$version.tgz" break fi done ;; osx* ) local tarball="mongodb-$sslbuild-$arch-enterprise-$version.tgz" ;; * ) local tarball="mongodb-$os-$arch-enterprise-$version.tgz" ;; esac version="$version-ent" local url="http://downloads.mongodb.com/$os/$tarball" fi debug "Default: $url" if ! good $url; then # Fallback to generic build if not already using this if [ "$sslbuild" != "$os" ]; then tarball="mongodb-$os-$arch-$version.tgz" url="http://fastdl.mongodb.org/$os/$tarball" debug "Fallback: $url" echo "Binary not available with SSL support. Checking url for generic (non-SSL) binaries." if ! good $url; then bin_not_supported $os-$arch $version $config exit 0; fi else bin_not_supported $os-$arch $version $config exit 0; fi fi pre install # perform the download local builddir="$BUILD_DIR_BASE$version" download $version $url $builddir # copy binaries to version directory local dir=$VERSIONS_DIR/$version mkdir -p $dir log "Moving binaries to $dir/bin" mv "$builddir/bin" $dir \ && cleanup "$builddir" \ && ln -sf $dir "$M_PREFIX/m/current" \ && post install } # # Set the os, distro, and arch variables for the current machine. # get_distro_and_arch() { arch=`uname -m` local OS=`uname` os=`echo $OS | tr '[:upper:]' '[:lower:]'` case $os in linux* ) os=linux ;; darwin* ) os=osx if [ "$arch" = "arm64" ]; then if [ $(numeric_version $version) -lt $(numeric_version "6.0.0") ]; then echo "" echo "NOTE: Apple Silicon is not natively supported for MongoDB server before 6.0" echo " ==> Changing detected architecture from arm64 to x86_64 so Rosetta 2 can be used" echo " More info: https://support.apple.com/en-au/HT211861" echo "" arch="x86_64" fi fi if [ $(numeric_version $version) -lt $(numeric_version "4.1.1") ]; then # https://jira.mongodb.org/browse/SERVER-35211 sslbuild="osx" # https://jira.mongodb.org/browse/SERVER-18421 if test "$community" = 1; then sslbuild="osx-ssl" else sslbuild="osx" fi else sslbuild="macos" fi ;; sunos* ) os=sunos5 ;; * ) bin_not_supported $OS $version $config ;; esac if [ -z ${sslbuild+x} ]; then sslbuild=$os fi local distro_id= distro_version= if lsb_release >/dev/null 2>&1; then # If the lsb_release(1) tool is installed, use it. distro_id=`lsb_release -si` distro_version=`lsb_release -sr` if test "$distro_version" = testing; then distro_version= fi fi if test -z "$distro_version"; then if test -f /etc/lsb-release; then # In the case where the distro provides an /etc/lsb-release file, but the lsb_release(1) util isn't installed. distro_id=$(sed -ne 's/^DISTRIB_ID=//p' /etc/lsb-release | sed -e 's/^["'"'"']//' -e 's/["'"'"']$//' -e 's/\\\(.\)/\1/g') distro_version=$(sed -ne 's/^DISTRIB_RELEASE=//p' /etc/lsb-release | sed -e 's/^["'"'"']//' -e 's/["'"'"']$//' -e 's/\\\(.\)/\1/g') elif test -f /etc/debian_version; then # Debian generally doesn't install lsb_release(1) or a /etc/lsb-release file, so we figure it out manually. distro_version=`cat /etc/debian_version` case "$distro_version" in etch|etch/*) distro_version=4 ;; lenny|lenny/*) distro_version=5 ;; squeeze|squeeze/*) distro_version=6 ;; wheezy|wheezy/*) distro_version=7 ;; jessie|jessie/*) distro_version=8 ;; stretch|stretch/*) distro_version=9 ;; buster|buster/*) distro_version=10 ;; bullseye|bullseye/*) distro_version=11 ;; bookworm|bookworm/*) distro_version=12 ;; esac distro_id=debian elif test -f /etc/os-release; then # Suse, opensuse, amazon linux, centos (but not redhat) distro_id=$(sed -ne 's/^ID=//p' /etc/os-release | sed -e 's/^["'"'"']//' -e 's/["'"'"']$//' -e 's/\\\(.\)/\1/g') distro_version=$(sed -ne 's/^VERSION_ID=//p' /etc/os-release | sed -e 's/^["'"'"']//' -e 's/["'"'"']$//' -e 's/\\\(.\)/\1/g') fi fi distro_id=`echo "$distro_id" | tr '[:upper:]' '[:lower:]'` distro_version=`echo "$distro_version" | tr '[:upper:]' '[:lower:]'` case "$distro_id" in sles) distro_id="suse" ;; opensuse) distro_id="suse" ;; almalinux) distro_id="rhel" ;; fedora) distro_id="rhel" ;; centos) distro_id="rhel" ;; redhatenterpriseserver) distro_id="rhel" ;; rocky) distro_id="rhel" ;; neon) distro_id="ubuntu" ;; esac distro="$distro_id-$distro_version" if test "$community" = 1; then amazon1="amazon" else amazon1="amzn64" fi debug "Detecting distro for $distro" # Different versions of MongoDB have builds for different distributions. # As m allows installing old MongoDB versions, we can look for # binaries for distributions that the latest MongoDB release is not # built for. Conversely, an old MongoDB version does not have to have # builds available for distributions that the latest version supports. # # The logic generally is to start with the correct distribution, then try # one version older and one version newer. This should handle most cases # reasonably well. case "$distro" in debian-6*) distros="" ;; debian-7*) distros="debian71" ;; debian-8*) distros="debian81 debian71" ;; debian-9*) distros="debian92 debian81" ;; debian-10*) distros="debian10 debian92" ;; debian-11*) distros="debian11 debian92" ;; debian-*) distros="debian11 debian10 debian92" ;; ubuntu-12*) distros="ubuntu1204 debian71" ;; ubuntu-14*) distros="ubuntu1404 ubuntu1204" ;; ubuntu-16*) distros="ubuntu1604 ubuntu1404" ;; ubuntu-18*) distros="ubuntu1804 ubuntu1604" ;; ubuntu-20*) distros="ubuntu2004 ubuntu1804" ;; ubuntu-22*) distros="ubuntu2204 ubuntu2004 ubuntu1804" ;; ubuntu-*) distros="ubuntu2204 ubuntu2004" ;; linuxmint-17*) distros="ubuntu1404" ;; linuxmint-18*) distros="ubuntu1604" ;; linuxmint-19*) distros="ubuntu1804" ;; linuxmint-20*) distros="ubuntu2004" ;; linuxmint-21*) distros="ubuntu2204" ;; suse-10*) distros="" ;; suse-11*) distros="suse11" ;; suse-12*) distros="suse12 suse11" ;; suse-15*) distros="suse15 suse12" ;; suse-*) distros="suse15 suse12" ;; amzn-1) distros="$amazon1 rhel70 rhel62" ;; amzn-2018.03) distros="$amazon1 rhel70 rhel62" ;; amzn-2) distros="amazon2 $amazon1 rhel70 rhel62" ;; amzn-*) distros="amazon2 $amazon1" ;; rhel-5*) distros="rhel55 rhel57" ;; rhel-6*) distros="rhel62 rhel55 rhel57 $amazon1" ;; rhel-7*) distros="rhel70 rhel62 $amazon1" ;; rhel-8*) distros="rhel80 rhel70 $amazon1" ;; rhel-8*) distros="rhel90 rhel80 rhel70" ;; rhel-*) distros="rhel90 rhel80 rhel70" ;; *) distros="" ;; esac if [ "$_legacy_only" = y ]; then distros="" fi } # # Determine if $url is good # good() { local url=$1 curl -Is $url | head -n 1 | grep 200 > /dev/null } # # Prompt when we cannot install binary # bin_not_supported() { local OS=$1 local version=$2 echo "" echo "----------------------------------------------------------------------------" echo "Prebuilt binaries for $OS $version do not appear to be available." echo "" echo "For supported platforms, please see:" echo " https://www.mongodb.com/docs/manual/administration/production-notes/" echo "" echo "To build from source, check the relevant build notes in GitHub:" echo " https://github.com/mongodb/mongo/blob/master/docs/building.md" echo "----------------------------------------------------------------------------" echo "" } # # Install from source # install_tarball() { local version=$1 local url=$2 local config=$3 bin_not_supported "$version" } # # Download and untar # download() { local version=$1 local url=$2 local builddir=$3 local logpath=`mktemp /tmp/m.XXXXXX` || exit 1 # create build directory mkdir -p $builddir if ! test -d $builddir; then abort "Failed to create directory ($builddir), do you have permissions to do this?" fi debug "download(): $GET $url" # fetch and unpack cd $builddir \ && $GET $url | tar xz --strip-components=1 > $logpath 2>&1 # see if things are alright if test $? -gt 0; then cd - cleanup "$builddir" printf "Error: installation failed\n" printf " MongoDB version $version does not exist,\n" printf " m failed to fetch the tarball,\n" printf " or tar failed. Try a different\n" printf " version or view $logpath to view\n" printf " error details.\n" exit 1 else rm $logpath fi cd - } # # Cleanup after the given # cleanup() { local dir=$1 if test -d $dir; then log "Cleaning up temporary files" debug "Removing working directory: $dir" rm -rf $dir fi } # # Remove # remove_versions() { test -z $1 && abort "version(s) required" check_current_version while test $# -ne 0; do local version=${1#v} local rmpath="$VERSIONS_DIR/$version" debug "=> Path: $rmpath" if test "$version" = "$active"; then printf "WARNING: $version is the active version!\n" read -p "Are you sure you want to remove this? [y/N] " yn case $yn in [Yy]* ) ;; * ) printf "SKIPPING $version "; exit;; esac fi if [ -d $rmpath ]; then rm -rf $rmpath echo "Removed MongoDB version $version" active="" else echo "MongoDB version $version is not installed" fi shift done } # # Output bin path for # display_bin_path_for_version() { test -z $1 && abort "version required" local version=$(get_latest_installed_version ${1#v}) local bin=$VERSIONS_DIR/$version/bin debug "Path: $bin" if test -f "$bin/mongod"; then echo $bin else abort_not_installed $1 fi } # # Get the latest installed version in a MongoDB release series (eg: "3.6", "3.6-ent") # get_latest_installed_version() { local version=$1 case $version in latest) version=`$0 --latest` ;; stable) version=`$0 --stable` ;; esac if [[ $version =~ ^([0-9)]\.([0-9]+)(-ent)?$ ]]; then local series="${BASH_REMATCH[1]}\.${BASH_REMATCH[2]}" local ent="${BASH_REMATCH[3]}" version=`find ${VERSIONS_DIR} -mindepth 1 -maxdepth 1 -type d \ | grep -E -o "$series\.[0-9]+([-_\.]rc[0-9]+)?" \ | sort -u -k 1,1n -k 2,2n -k 3,3n -t . \ | tail -n1` if [[ -z "$version" ]]; then echo "" else # append the enterprise label if included in the original version version="$version$ent" echo "$version" fi else echo "$version" fi } # # Execute the given of MongoDB # with [args ...] # execute_with_version() { test -z $1 && abort "version required" local version=$(get_latest_installed_version ${1#v}) local bin=$VERSIONS_DIR/$version/bin/mongod shift # remove version if test -f $bin; then $bin $@ else abort_not_installed $version fi } # # Execute the given of mongos # with [args ...] # execute_shard_with_version() { test -z $1 && abort "version required" local version=$(get_latest_installed_version ${1#v}) local bin=$VERSIONS_DIR/$version/bin/mongos shift # remove version if test -f $bin; then $bin $@ else abort_not_installed $version fi } # # Execute a script with the given shell of # MongoDB with [args...] # execute_shell_with_version() { test -z $1 && abort "version required" local version=$(get_latest_installed_version ${1#v}) local bin=$VERSIONS_DIR/$version/bin/mongo shift # remove version if test -f $bin; then $bin $@ else abort_not_installed $version fi } # # Display the latest MongoDB release version. # display_latest_version() { local version=$1 local all_versions="" get_all_versions if [[ $version =~ ^[0-9]\.[0-9]+$ ]]; then echo $all_versions \ | grep -E -o "$version\.[0-9]+([-_\.]rc[0-9]+)?" \ | grep -E -v "\d-\d" \ | uniq \ | sort -u -k 1,1n -k 2,2n -k 3,3n -t . \ | tail -n1 else if [[ ! -z "$version" ]]; then abort "Version [$version] does not match the MongoDB release series format (X.Y)" else echo $all_versions \ | grep -E -o '[0-9]\.[0-9]+\.[0-9]+([-_\.]rc[0-9]+)?' \ | grep -E -v "\d-\d" \ | uniq \ | sort -u -k 1,1n -k 2,2n -k 3,3n -t . \ | tail -n1 fi fi } # # Display the latest stable MongoDB release version. # display_latest_stable_version() { local version=$1 local all_versions="" get_all_versions if [[ $version =~ ^[0-4]\.[0246]+$ ]]; then debug "Stable version < 5.0 ($version) is X.Y (Y is even)" echo $all_versions \ | grep -E -o "$version\.[0-9]+" \ | grep -E -v "\d-\d" \ | uniq \ | sort -u -k 1,1n -k 2,2n -k 3,3n -t . \ | tail -n1 elif [[ $version =~ ^[5-9]\.0$ ]]; then debug "Stable version >= 5.0 ($version) is X.0" echo $all_versions \ | grep -E -o "$version\.[0-9]+" \ | grep -E -v "\d-\d" \ | uniq \ | sort -u -k 1,1n -k 2,2n -k 3,3n -t . \ | tail -n1 else if [[ ! -z "$version" ]]; then abort "Version [$version] does not match a stable MongoDB release series (X.Y)" else echo $all_versions \ | grep -E -o '[5-9]+\.0+\.[0-9]+\.zip' \ | grep -E -v "\d-\d" \ | uniq \ | sed s/.zip$// \ | sort -u -k 1,1n -k 2,2n -k 3,3n -t . \ | tail -n1 fi fi } # # Display the available MongoDB versions. # list_versions() { local version=$1 local stable=$2 check_current_version local all_versions="" local series="[0-9]\.[0-9]+" local rc="" # match by release series (eg: "3.6") if [[ $version =~ ^([0-9])\.([0-9]+) ]]; then series="${BASH_REMATCH[1]}\.${BASH_REMATCH[2]}" fi # Default to stable releases, with option to include RCs case $stable in latest|--latest|rc|--rc) rc="([-_\.]rc[0-9]+)?" ;; esac get_all_versions versions=`echo $all_versions \ | grep -E -o "$series\.[0-9]+$rc" \ | sort -u \ | sort -s -k 2.3n -t - \ | sort -s -k 1,1n -k 2,2n -k 3,3n -t . \ | awk '{ print " " $1 }'` if [[ -z "$versions" ]]; then abort "Could not find any releases for the requested version\n" fi for v in $versions; do if test "$active" = "$v"; then printf " ο $v\n" else if test -d $VERSIONS_DIR/$v; then printf " * $v\n" else printf " $v\n" fi fi done } # # Display src url for given . # list_src_url() { test -z $1 && abort "version required" local version=$1 local tarball="mongodb-src-r$version.tar.gz" local url="http://downloads.mongodb.org/src/$tarball" echo "$url" } # # store a hook # install_hook() { local hook=$1 local event=$2 local path=$3 local file="$M_DIR/$1_$2" #log "installing $1 hook into $file" touch $file validate_event $event # with no path, print all hooks if [ "" = "$path" ]; then if [ "pre" = $hook ]; then list_pres $event else list_posts $event fi exit 0 fi if [ "-" = $path ] || [ "rm" = $path ]; then # removing script or all scripts if [ "" = "$4" ]; then # remove all cat /dev/null > $file else # remove specified # skip sed & avoid path escaping issues touch tmp while read line do if ! [ $4 = $line ]; then echo $line >> tmp fi done < $file mv tmp $file fi else # add hook if ! test -x $path; then abort "not an executable file: $path" fi if ! [[ $path == /* ]]; then abort "not an absolute path: $path" fi # (ensure it exists only once) # skip sed & avoid path escaping issues while read line do if [ $path = $line ]; then exit 0 fi done < $file echo $path >> $file fi } # # validates hook type # {install,change} # validate_event() { if ! ([ "$1" = "install" ] || [ "$1" = "change" ]); then abort "invalid hook event: '$1'. Must be 'install' or 'change'." fi } # # executes pre hooks # pre() { local file=$M_DIR/pre_$1 if test -f $file; then while read line do $line done < $file fi } # # executes post hooks # post() { local file=$M_DIR/post_$1 if test -f $file; then while read line do $line done < $file fi } # # print all pre hooks # list_pres() { if test -f $M_DIR/pre_$1; then while read line do echo $line done < $M_DIR/pre_$1 fi } # # print all post hooks # list_posts() { if test -f $M_DIR/post_$1; then while read line do echo $line done < $M_DIR/post_$1 fi } # Handle tools commands handle_tools() { case $1 in ls|list|available|avail) list_tools_versions $@; exit;; lls|installed) display_tools_versions $2; exit ;; stable) install_tools $@; exit ;; *) install_tools $@; exit ;; esac } # Handle arguments if test $# -eq 0; then display_versions else while test $# -ne 0; do case $1 in -V|--version) display_m_version ;; -h|--help|help) display_help ;; lls|installed) display_versions $2; exit ;; --latest) display_latest_version $2; exit ;; --stable) display_latest_stable_version $2; exit ;; bin|which) display_bin_path_for_version $2; exit ;; as|use|mongod) shift; execute_with_version $@; exit ;; sd|shard|mongos) shift; execute_shard_with_version $@; exit ;; s|sh|shell|mongo) shift; execute_shell_with_version $@; exit ;; rm) shift; remove_versions $@; exit ;; latest) install_mongo `$0 --latest`; exit ;; stable) install_mongo `$0 --stable`; exit ;; ls|list|available|avail) shift; list_versions $@; exit ;; pre) shift; install_hook pre $@; exit ;; post) shift; install_hook post $@; exit ;; src) shift; list_src_url $@; exit;; install) shift; install_mongo $@; exit ;; reinstall) shift; CONFIRM=0; remove_versions $@; install_mongo $@; exit;; tools) shift; handle_tools $@; exit;; *) install_mongo $@; exit ;; esac shift done fi