diff --git a/salt-quick-start.ps1 b/salt-quick-start.ps1 new file mode 100644 index 000000000..25269b5fe --- /dev/null +++ b/salt-quick-start.ps1 @@ -0,0 +1,157 @@ +function Convert-PSObjectToHashtable { + param ( + [Parameter(ValueFromPipeline)] + $InputObject + ) + if ($null -eq $InputObject) { return $null } + + $is_enum = $InputObject -is [System.Collections.IEnumerable] + $not_string = $InputObject -isnot [string] + if ($is_enum -and $not_string) { + $collection = @( + foreach ($object in $InputObject) { + Convert-PSObjectToHashtable $object + } + ) + + Write-Host -NoEnumerate $collection + } elseif ($InputObject -is [PSObject]) { + $hash = @{} + + foreach ($property in $InputObject.PSObject.Properties) { + $hash[$property.Name] = Convert-PSObjectToHashtable $property.Value + } + + $hash + } else { + $InputObject + } +} + +function Expand-ZipFile { + # Extract a zip file + # + # Used by: + # - Install-SaltMinion + # + # Args: + # ZipFile (string): The file to extract + # Destination (string): The location to extract to + # + # Error: + # Sets the failed status and exits with a scriptFailed exit code + [CmdletBinding()] + param( + [Parameter(Mandatory = $true)] + [string] $ZipFile, + + [Parameter(Mandatory = $true)] + [string] $Destination + ) + + if (!(Test-Path -Path $Destination)) { + Write-Host "Creating missing directory: $Destination" + New-Item -ItemType directory -Path $Destination + } + Write-Host "Unzipping '$ZipFile' to '$Destination'" + if ($PSVersionTable.PSVersion.Major -ge 5) { + # PowerShell 5 introduced Expand-Archive + Write-Host "Using Expand-Archive to unzip" + try{ + Expand-Archive -Path $ZipFile -DestinationPath $Destination -Force + } catch { + Write-Host "Failed to unzip $ZipFile : $_" + exit 1 + } + } else { + # This method will work with older versions of powershell, but it is + # slow + Write-Host "Using Shell.Application to unzip" + $objShell = New-Object -Com Shell.Application + $objZip = $objShell.NameSpace($ZipFile) + try{ + foreach ($item in $objZip.Items()) { + $objShell.Namespace($Destination).CopyHere($item, 0x14) + } + } catch { + Write-Host "Failed to unzip $ZipFile : $_" + exit 1 + } + } + Write-Host "Finished unzipping '$ZipFile' to '$Destination'" +} + + +[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]'Tls12' + +$ProgressPreference = 'SilentlyContinue' + +$RepoUrl = "https://repo.saltproject.io/salt/py3/onedir" + +if ([IntPtr]::Size -eq 4) { + $arch = "x86" +} else { + $arch = "amd64" +} +$enc = [System.Text.Encoding]::UTF8 +try { + $response = Invoke-WebRequest -Uri "$RepoUrl/repo.json" -UseBasicParsing + if ($response.Content.GetType().Name -eq "Byte[]") { + $psobj = $enc.GetString($response.Content) | ConvertFrom-Json + + } else { + $psobj = $response.Content | ConvertFrom-Json + } + $hash = Convert-PSObjectToHashtable $psobj +} catch { + Write-Host "repo.json not found at: $RepoUrl" + $hash = @{} +} +$searchVersion = "latest" +if ( $hash.Contains($searchVersion)) { + foreach ($item in $hash.($searchVersion).Keys) { + if ( $item.EndsWith(".zip") ) { + if ( $item.Contains($arch) ) { + $saltFileName = $hash.($searchVersion).($item).name + $saltVersion = $hash.($searchVersion).($item).version + $saltSha512 = $hash.($searchVersion).($item).SHA512 + } + } + } +} +if ( $saltFileName -and $saltVersion -and $saltSha512 ) { + if ( $RepoUrl.Contains("minor") ) { + $saltFileUrl = @($RepoUrl, $saltVersion, $saltFileName) -join "/" + } else { + $saltFileUrl = @($RepoUrl, "minor", $saltVersion, $saltFileName) -join "/" + } +} + +Write-Host "Download Salt" +Invoke-WebRequest -Uri $saltFileUrl -OutFile .\salt.zip + +Write-Host "Extracting Salt" +Expand-ZipFile -ZipFile .\salt.zip -Destination . + +$PATH = $(Get-Location).Path + +$saltfile_contents = @" +salt-call: + local: True + config_dir: $PATH\salt\conf + log_file: $PATH\salt\var\log\salt\minion + cachedir: $PATH\salt\var\cache\salt + file_root: $PATH\salt\srv\salt +"@ + +Set-Content -Path .\salt\Saltfile -Value $saltfile_contents + +New-Item -Path "$PATH\salt\var\log\salt" -Type Directory -Force | Out-Null +New-Item -Path "$PATH\salt\conf" -Type Directory -Force | Out-Null +New-Item -Path "$PATH\salt\var\cache\salt" -Type Directory -Force | Out-Null +New-Item -Path "$PATH\salt\srv\salt" -Type Directory -Force | Out-Null + +Write-Host "Adding $PATH\salt to PATH" +$env:Path = "$PATH\salt;" + $env:Path + +$env:SALT_SALTFILE="$PATH\salt\Saltfile" diff --git a/salt-quick-start.sh b/salt-quick-start.sh new file mode 100755 index 000000000..3e17ce056 --- /dev/null +++ b/salt-quick-start.sh @@ -0,0 +1,239 @@ +#!/bin/sh + +__ScriptName="salt-quick-start.sh" +SALT_REPO_URL="https://repo.saltproject.io/salt/py3/onedir" +_COLORS=${QS_COLORS:-$(tput colors 2>/dev/null || echo 0)} + +_LOCAL=0 +_FULL=0 +_STOP=0 + +PWD="$(pwd)" +_PATH=${PWD}/salt + + +__usage() { + cat << EOT + + Usage : ${__ScriptName} [options] + + Options: + -h Show usage. + -f Full setup with a Salt minion and Salt master running. + -l Local setup, no Salt minion or Salt master running. + -s Attempt to stop a running Salt minion and Salt master. + +EOT +} # ---------- end of function __usage ---------- + + +echoinfo() { + printf "${GC} * INFO${EC}: %s\\n" "$@"; +} + +echoerror() { + printf "${RC} * ERROR${EC}: %s\\n" "$@" 1>&2; +} + +__detect_color_support() { + # shellcheck disable=SC2181 + if [ $? -eq 0 ] && [ "$_COLORS" -gt 2 ]; then + RC='\033[1;31m' + GC='\033[1;32m' + BC='\033[1;34m' + YC='\033[1;33m' + EC='\033[0m' + else + RC="" + GC="" + BC="" + YC="" + EC="" + fi +} + +__detect_color_support + +while getopts ':fhls' opt +do + case "${opt}" in + + h ) __usage; exit 0 ;; + l ) _LOCAL=1 ;; + f ) _FULL=1 ;; + s ) _STOP=1 ;; + + esac # --- end of case --- +done +shift $((OPTIND-1)) + +if [[ "${_STOP}" == "1" ]]; then + if [[ -f "${_PATH}/var/run/salt-minion.pid" ]]; then + echoinfo "Stopping the salt-minion" + kill $(cat "${_PATH}/var/run/salt-minion.pid") + else + echoerror "${_PATH}/var/run/salt-minion.pid not found" + fi + if [[ -f "${_PATH}/var/run/salt-master.pid" ]]; then + echoinfo "Stopping the salt-master" + kill $(cat "${_PATH}/var/run/salt-master.pid") + else + echoerror "${_PATH}/var/run/salt-master.pid not found" + fi + exit 0 +fi + +if [[ "$_LOCAL" == "1" && "$_FULL" == "1" ]]; then + echo "Only specify either local or full" + exit 0 +fi + +__parse_repo_json_jq() { + _JSON_FILE="${SALT_REPO_URL}/repo.json" + _JSON_VERSION=$(curl -s ${_JSON_FILE} | jq -sr ".[].latest[] | select(.os == \"$1\") | select(.arch == \"$2\").version") +} + +__fetch_url() { + # shellcheck disable=SC2086 + curl $_CURL_ARGS -L -s -f -o "$1" "$2" >/dev/null 2>&1 || + wget $_WGET_ARGS -q -O "$1" "$2" >/dev/null 2>&1 || + fetch $_FETCH_ARGS -q -o "$1" "$2" >/dev/null 2>&1 || # FreeBSD + fetch -q -o "$1" "$2" >/dev/null 2>&1 || # Pre FreeBSD 10 + ftp -o "$1" "$2" >/dev/null 2>&1 || # OpenBSD + (echoerror "$2 failed to download to $1"; exit 1) +} + +__gather_os_info() { + OS_NAME=$(uname -s 2>/dev/null) + OS_NAME_L=$( echo "$OS_NAME" | tr '[:upper:]' '[:lower:]' ) + OS_VERSION=$(uname -r) + # shellcheck disable=SC2034 + OS_VERSION_L=$( echo "$OS_VERSION" | tr '[:upper:]' '[:lower:]' ) +} + +__gather_hardware_info() { + if [ -f /proc/cpuinfo ]; then + CPU_VENDOR_ID=$(awk '/vendor_id|Processor/ {sub(/-.*$/,"",$3); print $3; exit}' /proc/cpuinfo ) + elif [ -f /usr/bin/kstat ]; then + # SmartOS. + # Solaris!? + # This has only been tested for a GenuineIntel CPU + CPU_VENDOR_ID=$(/usr/bin/kstat -p cpu_info:0:cpu_info0:vendor_id | awk '{print $2}') + else + CPU_VENDOR_ID=$( sysctl -n hw.model ) + fi + # shellcheck disable=SC2034 + CPU_VENDOR_ID_L=$( echo "$CPU_VENDOR_ID" | tr '[:upper:]' '[:lower:]' ) + CPU_ARCH=$(uname -m 2>/dev/null || uname -p 2>/dev/null || echo "unknown") + CPU_ARCH_L=$( echo "$CPU_ARCH" | tr '[:upper:]' '[:lower:]' ) +} + +__gather_hardware_info +__gather_os_info + +_DARWIN_ARM=0 +if [[ "${OS_NAME_L}" == "darwin" ]]; then + OS_NAME="macos" + # Use x86_64 packages until we are able build arm packages + if [[ "${CPU_ARCH_L}" == "arm64" ]]; then + CPU_ARCH_L="x86_64" + _DARWIN_ARM=1 + fi +else + OS_NAME="${OS_NAME_L}" +fi + +__parse_repo_json_jq ${OS_NAME} ${CPU_ARCH_L} + +FILE="salt-${_JSON_VERSION}-onedir-${OS_NAME_L}-${CPU_ARCH_L}.tar.xz" +URL="${SALT_REPO_URL}/latest/${FILE}" + +if [[ ! -f ${FILE} ]]; then + echoinfo "Downloading Salt" + __fetch_url "${FILE}" "${URL}" +fi + +if [[ ! -d "salt" ]]; then + echoinfo "Extracting Salt" + tar xf ${FILE} + + # very very hacky, remove ASAP + if [[ "${_DARWIN_ARM}" == "1" ]]; then + mkdir -p ${_PATH}/opt/openssl/lib + ln -s ${_PATH}/lib/libcrypto.dylib ${_PATH}/opt/openssl/lib/libcrypto.dylib + fi +else + echoinfo "A salt directory already exists here, not extracting." +fi + +mkdir -p ${_PATH}/etc/salt +mkdir -p ${_PATH}/srv/salt + +cat <${_PATH}/etc/salt/master +root_dir: ${_PATH} +file_root: ${_PATH}/srv/salt +EOT + +cat <${_PATH}/etc/salt/minion +root_dir: ${_PATH} +master: 127.0.0.1 +id: minion +EOT + +cat <${_PATH}/Saltfile +salt-call: + local: True + config_dir: ${_PATH} + log_file: ${_PATH}/var/log/salt/minion + cachedir: ${_PATH}/var/cache/salt + file_root: ${_PATH}/srv/salt + +salt-master: + config_dir: ${_PATH}/etc/salt + file_root: ${_PATH}/srv/salt + +salt-minion: + config_dir: ${_PATH}/etc/salt + file_root: ${_PATH}/srv/salt + +salt-key: + config_dir: ${_PATH}/etc/salt + +salt: + config_dir: ${_PATH}/etc/salt +EOT + +PATH_MSG="export PATH=${_PATH}" +PATH_MSG+=':$PATH' + +echoinfo "Get started with Salt by running the following commands" +echoinfo "Add Salt to current path" +echoinfo " ${PATH_MSG}" +echoinfo "Use the provided Saltfile" +echoinfo " export SALT_SALTFILE=${_PATH}/Saltfile" +# very very hacky, remove ASAP +if [[ "${_DARWIN_ARM}" == "1" ]]; then + echoinfo "Setup HOMEBREW" + echoinfo " export HOMEBREW_PREFIX=${_PATH}" +fi + +echoinfo "Create Salt states in ${_PATH}/srv/salt" + +if [[ "${_FULL}" == "1" ]]; then + + export PATH="${_PATH}:$PATH" + export SALT_SALTFILE="${_PATH}/Saltfile" + # very very hacky, remove ASAP + if [[ "${_DARWIN_ARM}" == "1" ]]; then + export HOMEBREW_PREFIX=${_PATH} + fi + echoinfo "Starting salt-master" + salt-master -d -c ${_PATH}/etc/salt + sleep 5 + echoinfo "Starting salt-minion" + salt-minion -d -c ${_PATH}/etc/salt + +echoinfo "Run salt-key -L to see pending minion keys" +echoinfo "Run salt-key -a minion to accept the pending minion key" + +fi