diff --git a/bootstrap-salt.ps1 b/bootstrap-salt.ps1 index 492353af9..49a079678 100644 --- a/bootstrap-salt.ps1 +++ b/bootstrap-salt.ps1 @@ -50,9 +50,13 @@ param( [Parameter(Mandatory=$false, ValueFromPipeline=$True)] [Alias("v")] - # The version of the Salt minion to install. Default is "latest" which will - # install the latest version of Salt minion available. Doesn't support - # versions prior to "YYYY.M.R-B" + # The version of the Salt minion to install. Use "latest" for the most recent + # GA (general availability) build at RepoUrl; prerelease directories (for + # example names containing "rc") are ignored for "latest" and for major-series + # selection. To install a prerelease build, pass the exact directory name + # shown at RepoUrl (for example "3008.0rc1"). Alternatively, specify a major + # version for the latest GA in that series (for example "3006"). Versions + # older than 3006 are not supported. [String]$Version = "latest", [Parameter(Mandatory=$false, ValueFromPipeline=$True)] @@ -153,6 +157,40 @@ function Get-MajorVersion { return ( $Version -split "\." )[0] } +function Test-SaltOnedirVersionIsGA { + # True if the onedir directory name is a GA CalVer (digits and dots only). + # Prerelease dirs (e.g. 3008.0rc1) are not GA; install those only via exact + # -Version matching the directory name. + [CmdletBinding()] + param( + [Parameter(Mandatory=$true)] + [String] $Version + ) + return [bool]( $Version -match '^\d+\.\d+(\.\d+)*$' ) +} + +function Compare-SaltCalVer { + # Compare two GA numeric CalVer strings (e.g. 3006.24 vs 3007.0). Returns 1 + # if Left is greater than Right, -1 if less, 0 if equal. + [CmdletBinding()] + param( + [Parameter(Mandatory=$true)] + [String] $Left, + [Parameter(Mandatory=$true)] + [String] $Right + ) + $left_parts = @( ($Left -split '\.') | ForEach-Object { [int]$_ } ) + $right_parts = @( ($Right -split '\.') | ForEach-Object { [int]$_ } ) + $max_len = [Math]::Max($left_parts.Count, $right_parts.Count) + for ( $i = 0; $i -lt $max_len; $i++ ) { + $a = if ( $i -lt $left_parts.Count ) { $left_parts[$i] } else { 0 } + $b = if ( $i -lt $right_parts.Count ) { $right_parts[$i] } else { 0 } + if ( $a -gt $b ) { return 1 } + if ( $a -lt $b ) { return -1 } + } + return 0 +} + function Get-AvailableVersions { # Get available versions from a remote location specified in the Source # Parameter @@ -163,7 +201,6 @@ function Get-AvailableVersions { if ( $base_url.StartsWith("http") -or $base_url.StartsWith("ftp") ) { # We're dealing with HTTP, HTTPS, or FTP - $response = Invoke-WebRequest "$base_url" -UseBasicParsing try { $response = Invoke-WebRequest "$base_url" -UseBasicParsing } catch { @@ -177,19 +214,15 @@ function Get-AvailableVersions { exit 1 } - $response.links | ForEach-Object { - if ( $_.href.Length -gt 8) { - Write-Host "The content at this location is unexpected" -ForegroundColor Red - Write-Host "Should be a list of directories where the name is a version of Salt" -ForegroundColor Red - exit 1 - } - } - - # Getting available versions from response + # Getting available versions from response (Salt dirs: 3006.24, 3008.0, + # 3008.0rc1, etc.). Skip non-version links from the index page. Write-Verbose "Getting available versions from response" $filtered = $response.Links | Where-Object -Property href -NE "../" - $filtered | Select-Object -Property href | ForEach-Object { - $available_versions.Add($_.href.Trim("/")) | Out-Null + $filtered | ForEach-Object { + $name = $_.href.Trim("/") + if ( $name -match '^\d+\.\d+' ) { + $available_versions.Add($name) | Out-Null + } } } elseif ( $base_url.StartsWith("\\") -or $base_url -match "^[A-Za-z]:\\" ) { # We're dealing with a local directory or SMB source @@ -202,34 +235,42 @@ function Get-AvailableVersions { exit 1 } + if ( $available_versions.Count -eq 0 ) { + Write-Host "No version directories found at RepoUrl" -ForegroundColor Red + Write-Host "base_url: $base_url" -ForegroundColor Red + exit 1 + } + Write-Verbose "Available versions:" $available_versions | ForEach-Object { Write-Verbose "- $_" } # Create a versions table - # This will have the latest version available, the latest version available - # for each major version, and every version available. This makes the - # version lookup logic easier. The contents of the versions table can be - # found by running -Verbose + # "latest" and each major-series key (3006, 3007, ...) use the newest GA + # build only; prerelease dirs still appear under their exact names. Every + # discovered directory name is also stored lowercased for lookup. The + # contents of the versions table can be found by running -Verbose Write-Verbose "Populating the versions table" $versions_table = [ordered]@{} $available_versions | ForEach-Object { $major_version = $(Get-MajorVersion $_) - if ( $versions_table.Keys -contains $major_version ) { - if ( [System.Version]$_ -gt [System.Version]$versions_table[$major_version] ) { + if ( Test-SaltOnedirVersionIsGA $_ ) { + if ( $versions_table.Keys -contains $major_version ) { + if ( (Compare-SaltCalVer $_ $versions_table[$major_version]) -gt 0 ) { + $versions_table[$major_version] = $_ + } + } else { $versions_table[$major_version] = $_ } - } else { - $versions_table[$major_version] = $_ - } - if ( $versions_table -contains "latest" ) { - if ( [System.Version]$_ -gt [System.Version]$versions_table["latest"] ) { + if ( $versions_table.Keys -contains "latest" ) { + if ( (Compare-SaltCalVer $_ $versions_table["latest"]) -gt 0 ) { + $versions_table["latest"] = $_ + } + } else { $versions_table["latest"] = $_ } - } else { - $versions_table["latest"] = $_ } $versions_table[$_.ToLower()] = $_.ToLower() diff --git a/bootstrap-salt.sh b/bootstrap-salt.sh index 9324a0170..8d5b57f5f 100755 --- a/bootstrap-salt.sh +++ b/bootstrap-salt.sh @@ -515,6 +515,7 @@ fi # What ever is written to the logpipe gets written to the logfile tee < "$LOGPIPE" "$LOGFILE" & +TEE_PID=$! # Close STDOUT, reopen it directing it to the logpipe exec 1>&- @@ -571,10 +572,10 @@ __exit_cleanup() { fi # Kill tee when exiting, CentOS, at least requires this - # shellcheck disable=SC2009 - TEE_PID=$(ps ax | grep tee | grep "$LOGFILE" | awk '{print $1}') - - [ "$TEE_PID" = "" ] && exit $EXIT_CODE + if [ "$TEE_PID" = "" ]; then + exec >/dev/null 2>&1 + exit "$EXIT_CODE" + fi echodebug "Killing logging pipe tee's with pid(s): $TEE_PID" @@ -587,11 +588,13 @@ __exit_cleanup() { } trap "__trap_errors" INT ABRT QUIT TERM - # Now we're "good" to kill tee + # Detach stdout/stderr from LOGPIPE before killing tee so shell teardown does + # not write to a pipe with no reader (SIGPIPE / exit 141 under docker exec -e). + exec >/dev/null 2>&1 kill -s TERM "$TEE_PID" # In case the 127 errno is not triggered, exit with the "original" exit code - exit $EXIT_CODE + exit "$EXIT_CODE" } trap "__exit_cleanup" EXIT INT @@ -6385,6 +6388,15 @@ EOF # Photon OS Install Functions # +#--- FUNCTION ------------------------------------------------------------------------------------------------------- +# NAME: __salt_onedir_filter_ga_version_dirs +# DESCRIPTION: From stdin: keep only GA CalVer-style directory names (digits and dots; +# prerelease dirs like 3008.0rc1 are excluded). +#---------------------------------------------------------------------------------------------------------------------- +__salt_onedir_filter_ga_version_dirs() { + grep -E '^[0-9]+\.[0-9]+(\.[0-9]+)*$' +} + #--- FUNCTION ------------------------------------------------------------------------------------------------------- # NAME: __rpm_get_packagesite_onedir_latest # DESCRIPTION: Set _GENERIC_PKG_VERSION to the latest for RPM or latest for major version input @@ -6393,26 +6405,35 @@ __get_packagesite_onedir_latest() { echodebug "Find latest rpm release from repository" - # get dir listing from url, sort and pick highest generic_versions_tmpdir=$(mktemp -d) curr_pwd=$(pwd) - cd ${generic_versions_tmpdir} || return 1 + cd "${generic_versions_tmpdir}" || return 1 # leverage the windows directories since release Windows and Linux wget -q -r -np -nH --exclude-directories=onedir,relenv,macos -x -l 1 "https://${_REPO_URL}/saltproject-generic/windows/" if [ "$#" -gt 0 ] && [ -n "$1" ]; then MAJOR_VER="$1" # shellcheck disable=SC2010 - _GENERIC_PKG_VERSION=$(ls artifactory/saltproject-generic/windows/ | grep -v 'index.html' | sort -V -u | grep -E "$MAJOR_VER" | tail -n 1) + _GENERIC_PKG_VERSION=$(ls artifactory/saltproject-generic/windows/ | grep -v 'index.html' | __salt_onedir_filter_ga_version_dirs | grep -E "^${MAJOR_VER}\\." | sort -V -u | tail -n 1) else # shellcheck disable=SC2010 - _GENERIC_PKG_VERSION=$(ls artifactory/saltproject-generic/windows/ | grep -v 'index.html' | sort -V -u | tail -n 1) + _GENERIC_PKG_VERSION=$(ls artifactory/saltproject-generic/windows/ | grep -v 'index.html' | __salt_onedir_filter_ga_version_dirs | sort -V -u | tail -n 1) + fi + cd "${curr_pwd}" || return 1 + rm -fR "${generic_versions_tmpdir}" + + if [ -z "${_GENERIC_PKG_VERSION}" ]; then + if [ "$#" -gt 0 ] && [ -n "$1" ]; then + echoerror "No GA Salt onedir version found for major series $1 (prerelease dirs are ignored for this selection)." + else + echoerror "No GA Salt onedir version found for latest (prerelease dirs are ignored for this selection)." + fi + return 1 fi - cd ${curr_pwd} || return "${_GENERIC_PKG_VERSION}" - rm -fR ${generic_versions_tmpdir} echodebug "latest rpm release from repository found ${_GENERIC_PKG_VERSION}" + return 0 } @@ -6756,7 +6777,7 @@ install_vmware_photon_os_onedir() { if [ "$(echo "$STABLE_REV" | grep -E '^(3006|3007)$')" != "" ]; then # Major version Salt, config and repo already setup - __get_packagesite_onedir_latest "$STABLE_REV" + __get_packagesite_onedir_latest "$STABLE_REV" || return 1 MINOR_VER_STRG="-$_GENERIC_PKG_VERSION" elif [ "$(echo "$STABLE_REV" | grep -E '^([3-9][0-5]{2}[6-9](\.[0-9]*)?)')" != "" ]; then # Minor version Salt, need to add specific minor version @@ -6764,7 +6785,7 @@ install_vmware_photon_os_onedir() { MINOR_VER_STRG="-$STABLE_REV_DOT" else # default to latest version Salt, config and repo already setup - __get_packagesite_onedir_latest + __get_packagesite_onedir_latest || return 1 MINOR_VER_STRG="-$_GENERIC_PKG_VERSION" fi @@ -7838,24 +7859,33 @@ __macosx_get_packagesite_onedir_latest() { echodebug "Find latest MacOS release from repository" - # get dir listing from url, sort and pick highest macos_versions_tmpdir=$(mktemp -d) curr_pwd=$(pwd) - cd ${macos_versions_tmpdir} || return 1 + cd "${macos_versions_tmpdir}" || return 1 wget -q -r -np -nH --exclude-directories=onedir,relenv,windows -x -l 1 "$SALT_MACOS_PKGDIR_URL/" if [ "$#" -gt 0 ] && [ -n "$1" ]; then MAJOR_VER="$1" # shellcheck disable=SC2010 - _PKG_VERSION=$(ls artifactory/saltproject-generic/macos/ | grep -v 'index.html' | sort -V -u | grep -E "$MAJOR_VER" | tail -n 1) + _PKG_VERSION=$(ls artifactory/saltproject-generic/macos/ | grep -v 'index.html' | __salt_onedir_filter_ga_version_dirs | grep -E "^${MAJOR_VER}\\." | sort -V -u | tail -n 1) else # shellcheck disable=SC2010 - _PKG_VERSION=$(ls artifactory/saltproject-generic/macos/ | grep -v 'index.html' | sort -V -u | tail -n 1) + _PKG_VERSION=$(ls artifactory/saltproject-generic/macos/ | grep -v 'index.html' | __salt_onedir_filter_ga_version_dirs | sort -V -u | tail -n 1) + fi + cd "${curr_pwd}" || return 1 + rm -fR "${macos_versions_tmpdir}" + + if [ -z "${_PKG_VERSION}" ]; then + if [ "$#" -gt 0 ] && [ -n "$1" ]; then + echoerror "No GA Salt macOS onedir version found for major series $1 (prerelease dirs are ignored for this selection)." + else + echoerror "No GA Salt macOS onedir version found for latest (prerelease dirs are ignored for this selection)." + fi + return 1 fi - cd ${curr_pwd} || return "${_PKG_VERSION}" - rm -fR ${macos_versions_tmpdir} echodebug "latest MacOS release from repository found ${_PKG_VERSION}" + return 0 } @@ -7874,15 +7904,15 @@ __macosx_get_packagesite_onedir() { _ONEDIR_TYPE="saltproject-generic" SALT_MACOS_PKGDIR_URL="https://${_REPO_URL}/${_ONEDIR_TYPE}/macos" if [ "$(echo "$_ONEDIR_REV" | grep -E '^(latest)$')" != "" ]; then - __macosx_get_packagesite_onedir_latest + __macosx_get_packagesite_onedir_latest || return 1 elif [ "$(echo "$_ONEDIR_REV" | grep -E '^(3006|3007)$')" != "" ]; then # need to get latest for major version - __macosx_get_packagesite_onedir_latest "$_ONEDIR_REV" + __macosx_get_packagesite_onedir_latest "$_ONEDIR_REV" || return 1 elif [ "$(echo "$_ONEDIR_REV" | grep -E '^([3-9][0-9]{3}(\.[0-9]*)?)')" != "" ]; then _PKG_VERSION=$_ONEDIR_REV else # default to getting latest - __macosx_get_packagesite_onedir_latest + __macosx_get_packagesite_onedir_latest || return 1 fi PKG="salt-${_PKG_VERSION}-py3-${DARWIN_ARCH}.pkg"