workerLabel="[Worker]" taskStatusExecution="execution" taskStatusSuccess="success" taskStatusFailed="failed" taskStatusWaiting="waiting" taskStatusNew="new" # Prepares worker agent directory and UUID file. function cmdWorkerPreparation() { printInfo "$workerLabel Preparation..." if [[ ! -f "$workerAgentPath/worker.py" ]]; then mkdir -p "$workerAgentPath" cp -f -- "$appAssetsPath/$workerKube/worker.py" "$workerAgentPath/worker.py" fi rm -f "$workerAgentPath/worker.uuid" fileValueGetOrCreate "$workerAgentPath/worker.uuid" "$hostUuid" >/dev/null 2>&1 || { printDanger "$workerLabel Generation UUID failed" return 1 } printSuccess "$workerLabel Preparatory completed" } # Renders the Worker Kubernetes YAML manifest via Helm. function cmdWorkerYamlRender() { printInfo "$workerLabel Render YAML | Helm" local templateFile="templates/$workerKube.yaml" [[ -f "$appAssetsPath/k3s/$templateFile" ]] || { printDanger "$workerLabel Template YAML : File not found | $appAssetsPath/k3s/$templateFile" return 1 } printInfo "$workerLabel Template YAML : $appAssetsPath/k3s/$templateFile" local varsFile varsFile=$(mktemp "/tmp/$workerKube.vars.XXXXXX.yaml") || return 1 printInfo "$workerLabel Variables : $varsFile" trap 'rm -f -- "$varsFile"' RETURN cat > "$varsFile" < "$workerYaml" || { printDanger "$workerLabel Render failed" return 1 } printSuccess "$workerLabel Render completed" } # Installs Worker into Kubernetes. function cmdWorkerInstall() { cmdWorkerPreparation || return 1 cmdWorkerYamlRender || return 1 cmdK3sYamlApplyEx "$workerYaml" } # Uninstalls Worker Kubernetes resources. function cmdWorkerUninstall() { "$k3sCmd" kubectl delete -f "$workerYaml" } # Updates worker env vars, prints new values, and restarts the deployment. function cmdWorkerReload() { cmdWorkerEnvUpdate || return 1 printInfo "$workerLabel Updated ENV:" workerEnvGet || return 1 workerRestart } # Executes one worker task described in an INI-like config file. # $1 (taskFile): path to the task config file. # [$2] (domain): override domain (read from task file if omitted). function cmdWorkerTaskHandle() { local taskFile="$1" [[ -n "$taskFile" ]] || { printDanger "$workerLabel Task file not specified"; return 1; } [[ -f "$taskFile" ]] || { printDanger "$workerLabel Task: $taskFile | File not found"; return 1; } printInfo "$workerLabel Task: $taskFile" local domain="$2" [[ -n "$domain" ]] || domain=$(configGet "$taskFile" "domain") local status status=$(configGet "$taskFile" "status") if [[ "$status" != "$taskStatusNew" && "$status" != "$taskStatusWaiting" ]]; then printDanger "$workerLabel Task: $taskFile | Status not '$taskStatusNew' or '$taskStatusWaiting'" return 1 fi configSet "$taskFile" "status" "$taskStatusExecution" configSet "$taskFile" "start" "$(date +%s)" local action action=$(configGet "$taskFile" "action") printInfo "$workerLabel Action: $action" case "$action" in "copy") local databaseUrl databaseUrl=$(configGet "$taskFile" "database_url") if ! run output error urlAccessible "$databaseUrl"; then printDanger "$workerLabel URL database archive is invalid: $databaseUrl" configSet "$taskFile" "status" "$taskStatusFailed" configSet "$taskFile" "message" "URL database archive is invalid: $databaseUrl" return 1 fi local filesUrl filesUrl=$(configGet "$taskFile" "files_url") if ! run output error urlAccessible "$filesUrl"; then printDanger "$workerLabel URL files archive is invalid: $filesUrl" configSet "$taskFile" "status" "$taskStatusFailed" configSet "$taskFile" "message" "URL files archive is invalid: $filesUrl" return 1 fi if [[ -z "$domain" ]]; then domain=$(domainsListMark "$domainsList") fi if [[ -z "$domain" ]]; then printDanger "$workerLabel Domain not specified or no domains available" configSet "$taskFile" "status" "$taskStatusFailed" configSet "$taskFile" "message" "Domain not specified or no domains available" return 1 else configSet "$taskFile" "domain" "$domain" fi configSet "$taskFile" "status" "$taskStatusExecution" mkdir -p "$workerFilesPath" local fileName filesLocal databaseLocal fileName="${domain}_$(uuidgen)" databaseLocal="$workerFilesPath/$(urlLocalFileGen "$databaseUrl" "$fileName")" printInfo "$workerLabel Download archive database --> $databaseLocal" if ! run output error fileDownload "$databaseUrl" "$databaseLocal"; then printDanger "$error" configSet "$taskFile" "status" "$taskStatusFailed" configSet "$taskFile" "message" "$error" return 1 fi filesLocal="$workerFilesPath/$(urlLocalFileGen "$filesUrl" "$fileName")" printInfo "$workerLabel Download archive files --> $filesLocal" if ! run output error fileDownload "$filesUrl" "$filesLocal"; then printDanger "$error" configSet "$taskFile" "status" "$taskStatusFailed" configSet "$taskFile" "message" "$error" return 1 fi printInfo "$workerLabel Create site: $domain" if ! run output error cmdSiteAddWordpress "$domain" "$filesLocal" "$databaseLocal"; then printDanger "$error" configSet "$taskFile" "status" "$taskStatusFailed" configSet "$taskFile" "message" "Error create site: $error" return 1 else cmdWordpressDomainUpdate "$domain" cmdOpenlitespeedRestart fi ;; "pack") local output error local uuid="worker_$(uuidgen)" if ! run vhostList error openlitespeedVhostList; then printDanger "Vhost list: $error" configSet "$taskFile" "status" "$taskStatusFailed" configSet "$taskFile" "message" "Error getting list of virtual hosts" return 1 elif ! listContains "$domain" "$vhostList"; then printDanger "Vhost list: Domain is not exists in OpenLiteSpeed config" configSet "$taskFile" "status" "$taskStatusFailed" configSet "$taskFile" "message" "Domain is not exists in OpenLiteSpeed config" return 1 fi if ! run output error backupSiteFiles "$domain" "$vhostsPath/$domain/www/$uuid"; then printDanger "$error" configSet "$taskFile" "status" "$taskStatusFailed" configSet "$taskFile" "message" "Error create files archive: $error" return 1 fi if ! run output error backupSiteDatabase "$domain" "$vhostsPath/$domain/www/$uuid.sql"; then printDanger "$error" configSet "$taskFile" "status" "$taskStatusFailed" configSet "$taskFile" "message" "Error create database archive: $error" return 1 fi configSet "$taskFile" "files_url" "https://$domain/$uuid.tar.gz" configSet "$taskFile" "database_url" "https://$domain/$uuid.sql.tar.gz" ;; "delete") printSuccess "$workerLabel Action: Site delete..." cmdSiteRemove "$domain" cmdOpenlitespeedRestart ;; "update") domain=$(configGet "$taskFile" "domain") if [[ -z "$domain" ]]; then printDanger "$workerLabel Domain not specified" configSet "$taskFile" "status" "$taskStatusFailed" configSet "$taskFile" "message" "Domain not specified" return 1 fi local domainList domainList=$(postfixDomainList) if ! listContains "$domain" "$domainList"; then printDanger "$workerLabel Domain $domain not found" configSet "$taskFile" "status" "$taskStatusFailed" configSet "$taskFile" "message" "Domain $domain not found" return 1 fi local postfixForwardTo postfixForwardTo=$(configGet "$taskFile" "mail_forward_to") siteConfigSet "$domain" "postfixForwardTo" "$postfixForwardTo" postfixVirtualAliasSet "@$domain" "$postfixForwardTo" postfixPostmapRebuild ;; *) printDanger "$workerLabel Unknown action: $action" configSet "$taskFile" "status" "$taskStatusFailed" configSet "$taskFile" "message" "Unknown action: $action" return 1 ;; esac configSet "$taskFile" "status" "$taskStatusSuccess" printSuccess "$workerLabel Action: $action | Success" local taskFileBase taskFileBase=$(basename -- "$taskFile") mkdir -p "$appDataPath/worker-task" || true cp -f -- "$taskFile" "$appDataPath/worker-task/$taskFileBase" 2>/dev/null || true } # Scans task dir and runs handler for tasks with status new or waiting. function cmdWorkerObserver() { local fileList error run fileList error fileList "$workerTasksPath" f || { appError "$error"; return 1; } while IFS= read -r file; do local taskFile="$workerTasksPath/$file" local status status=$(configGet "$taskFile" "status") if [[ "$status" == "$taskStatusNew" || "$status" == "$taskStatusWaiting" ]]; then printSuccess "$workerLabel $file | Status: $status | Starting..." cmdWorkerTaskHandle "$taskFile" else printInfo "$workerLabel $file | Status: $status | Skip" fi done < <(awk 'NF' <<< "$fileList") } # Lists worker tasks with action, status, and lifetime in seconds. function cmdWorkerTaskList() { local fileList error run fileList error fileList "$workerTasksPath" f || { appError "$error"; return 1; } if [[ -z "$fileList" ]]; then printInfo "$workerLabel Tasks not found" return 0 fi log "# | Task | Action | Status | Time, sec" log "$(printf -- '-%.0s' {1..75})" local count=0 while IFS= read -r file; do ((count++)) local task=${file%.worker} local action status start action=$(configGet "$workerTasksPath/$file" "action") status=$(configGet "$workerTasksPath/$file" "status") start=$(configGet "$workerTasksPath/$file" "start") local live="?" if [[ -n "$start" ]]; then live=$(( $(date +%s) - start )) fi printf "%1s | %-36s | %-7s | %-9s | %s\n" "$count" "$task" "$action" "$status" "$live" done < <(awk 'NF' <<< "$fileList") } # Updates worker deployment env vars; rolls back on failure. function cmdWorkerEnvUpdate() { local output error run output error k3sRun set env deployment/"$workerKube" --containers="$workerKube" \ WORKER_UUID="$hostUuid" \ WORKER_NAME="$workerName" \ WORKER_POOL="$workerPool" \ API_URL="$workerApiUrl" \ GETTING_PAUSE="$workerApiGettingPause" \ SENDING_PAUSE="$workerApiSendingPause" || { appError "$error"; return 1; } if ! run output error k3sRun rollout status deployment/"$workerKube" --timeout=2m; then printDanger "$workerLabel $error" printDanger "$workerLabel Rollout undo..." k3sRun rollout undo deployment/"$workerKube" return 1 fi }