-
-
Notifications
You must be signed in to change notification settings - Fork 5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Truenas deploy websocket #6108
Open
Attackwave
wants to merge
9
commits into
acmesh-official:dev
Choose a base branch
from
Attackwave:Truenas-Deploy-Websocket
base: dev
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Truenas deploy websocket #6108
Changes from 7 commits
Commits
Show all changes
9 commits
Select commit
Hold shift + click to select a range
75b4bb3
Merge pull request #6096 from acmesh-official/dev
Neilpang 413a916
Create truenas_ws.sh
Attackwave 5d6f1bd
Merge pull request #6110 from acmesh-official/dev
Neilpang 1e52efa
Merge branch 'acmesh-official:master' into Truenas-Deploy-Websocket
Attackwave d7855e8
Update truenas_ws.sh (shfmt and shellcheck)
Attackwave f2a311b
Update truenas_ws.sh (added return instead exit)
Attackwave 9110375
Update truenas_ws.sh (fixed shfmt)
Attackwave 4424033
Update truenas_ws.sh (Interpreter changed from bash to sh)
Attackwave ebaf4c9
Update truenas_ws.sh (Output new certificate name)
Attackwave File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,293 @@ | ||
#!/usr/bin/env bash | ||
|
||
# TrueNAS deploy script for SCALE/CORE using websocket | ||
# It is recommend to use a wildcard certificate | ||
# | ||
# Websocket Documentation: https://www.truenas.com/docs/api/scale_websocket_api.html | ||
# | ||
# Tested with TrueNAS Scale - Electric Eel 24.10 | ||
# Changes certificate in the following services: | ||
# - Web UI | ||
# - FTP | ||
# - iX Apps | ||
# | ||
# The following environment variables must be set: | ||
# ------------------------------------------------ | ||
# | ||
# # API KEY | ||
# # Use the folowing URL to create a new API token: <TRUENAS_HOSTNAME OR IP>/ui/apikeys | ||
# export DEPLOY_TRUENAS_APIKEY="<API_KEY_GENERATED_IN_THE_WEB_UI" | ||
# | ||
|
||
### Private functions | ||
|
||
# Call websocket method | ||
# Usage: | ||
# _ws_response=$(_ws_call "math.dummycalc" "'{"x": 4, "y": 5}'") | ||
# _info "$_ws_response" | ||
# | ||
# Output: | ||
# {"z": 9} | ||
# | ||
# Arguments: | ||
# $@ - midclt arguments for call | ||
# | ||
# Returns: | ||
# JSON/JOBID | ||
_ws_call() { | ||
_debug "_ws_call arg1" "$1" | ||
_debug "_ws_call arg2" "$2" | ||
_debug "_ws_call arg3" "$3" | ||
if [ $# -eq 3 ]; then | ||
_ws_response=$(midclt -K "$DEPLOY_TRUENAS_APIKEY" call "$1" "$2" "$3") | ||
fi | ||
if [ $# -eq 2 ]; then | ||
_ws_response=$(midclt -K "$DEPLOY_TRUENAS_APIKEY" call "$1" "$2") | ||
fi | ||
if [ $# -eq 1 ]; then | ||
_ws_response=$(midclt -K "$DEPLOY_TRUENAS_APIKEY" call "$1") | ||
fi | ||
_debug "_ws_response" "$_ws_response" | ||
printf "%s" "$_ws_response" | ||
return 0 | ||
} | ||
|
||
# Check argument is a number | ||
# Usage: | ||
# | ||
# Output: | ||
# n/a | ||
# | ||
# Arguments: | ||
# $1 - Anything | ||
# | ||
# Returns: | ||
# 0: true | ||
# 1: false | ||
_ws_check_jobid() { | ||
case "$1" in | ||
[0-9]*) | ||
return 0 | ||
;; | ||
esac | ||
return 1 | ||
} | ||
|
||
# Wait for job to finish and return result as JSON | ||
# Usage: | ||
# _ws_result=$(_ws_get_job_result "$_ws_jobid") | ||
# _new_certid=$(printf "%s" "$_ws_result" | jq -r '."id"') | ||
# | ||
# Output: | ||
# JSON result of the job | ||
# | ||
# Arguments: | ||
# $1 - JobID | ||
# | ||
# Returns: | ||
# n/a | ||
_ws_get_job_result() { | ||
while true; do | ||
sleep 2 | ||
_ws_response=$(_ws_call "core.get_jobs" "[[\"id\", \"=\", $1]]") | ||
if [ "$(printf "%s" "$_ws_response" | jq -r '.[]."state"')" != "RUNNING" ]; then | ||
_ws_result="$(printf "%s" "$_ws_response" | jq '.[]."result"')" | ||
_debug "_ws_result" "$_ws_result" | ||
printf "%s" "$_ws_result" | ||
_ws_error="$(printf "%s" "$_ws_response" | jq '.[]."error"')" | ||
if [ "$_ws_error" != "null" ]; then | ||
_err "Job $1 failed:" | ||
_err "$_ws_error" | ||
return 7 | ||
fi | ||
break | ||
fi | ||
done | ||
return 0 | ||
} | ||
|
||
######################## | ||
### Public functions ### | ||
######################## | ||
|
||
# truenas_ws_deploy | ||
# | ||
# Deploy new certificate to TrueNAS services | ||
# | ||
# Arguments | ||
# 1: Domain | ||
# 2: Key-File | ||
# 3: Certificate-File | ||
# 4: CA-File | ||
# 5: FullChain-File | ||
# Returns: | ||
# 0: Success | ||
# 1: Missing API Key | ||
# 2: TrueNAS not ready | ||
# 3: Not a JobID | ||
# 4: FTP cert error | ||
# 5: WebUI cert error | ||
# 6: Job error | ||
# 7: WS call error | ||
# 10: No CORE or SCALE detected | ||
# | ||
truenas_ws_deploy() { | ||
_domain="$1" | ||
_file_key="$2" | ||
_file_cert="$3" | ||
_file_ca="$4" | ||
_file_fullchain="$5" | ||
_debug _domain "$_domain" | ||
_debug _file_key "$_file_key" | ||
_debug _file_cert "$_file_cert" | ||
_debug _file_ca "$_file_ca" | ||
_debug _file_fullchain "$_file_fullchain" | ||
|
||
########## Environment check | ||
|
||
_info "Checking environment variables..." | ||
_getdeployconf DEPLOY_TRUENAS_APIKEY | ||
# Check API Key | ||
if [ -z "$DEPLOY_TRUENAS_APIKEY" ]; then | ||
_err "TrueNAS API key not found, please set the DEPLOY_TRUENAS_APIKEY environment variable." | ||
return 1 | ||
fi | ||
_secure_debug2 DEPLOY_TRUENAS_APIKEY "$DEPLOY_TRUENAS_APIKEY" | ||
_info "Environment variables: OK" | ||
|
||
########## Health check | ||
|
||
_info "Checking TrueNAS health..." | ||
_ws_response=$(_ws_call "system.ready" | tr '[:lower:]' '[:upper:]') | ||
_ws_ret=$? | ||
if [ $_ws_ret -gt 0 ]; then | ||
_err "Error calling system.ready:" | ||
_err "$_ws_response" | ||
return $_ws_ret | ||
fi | ||
|
||
if [ "$_ws_response" != "TRUE" ]; then | ||
_err "TrueNAS is not ready." | ||
_err "Please check environment variables DEPLOY_TRUENAS_APIKEY, DEPLOY_TRUENAS_HOSTNAME and DEPLOY_TRUENAS_PROTOCOL." | ||
_err "Verify API key." | ||
return 2 | ||
fi | ||
_savedeployconf DEPLOY_TRUENAS_APIKEY "$DEPLOY_TRUENAS_APIKEY" | ||
_info "TrueNAS health: OK" | ||
|
||
########## System info | ||
|
||
_info "Gather system info..." | ||
_ws_response=$(_ws_call "system.info") | ||
_truenas_system=$(printf "%s" "$_ws_response" | jq -r '."version"' | cut -d '-' -f 2 | tr '[:lower:]' '[:upper:]') | ||
_truenas_version=$(printf "%s" "$_ws_response" | jq -r '."version"' | cut -d '-' -f 3) | ||
_info "TrueNAS system: $_truenas_system" | ||
_info "TrueNAS version: $_truenas_version" | ||
if [ "$_truenas_system" != "SCALE" ] && [ "$_truenas_system" != "CORE" ]; then | ||
_err "Cannot gather TrueNAS system. Nor CORE oder SCALE detected." | ||
return 10 | ||
fi | ||
|
||
########## Gather current certificate | ||
|
||
_info "Gather current WebUI certificate..." | ||
_ws_response="$(_ws_call "system.general.config")" | ||
_ui_certificate_id=$(printf "%s" "$_ws_response" | jq -r '."ui_certificate"."id"') | ||
_ui_certificate_name=$(printf "%s" "$_ws_response" | jq -r '."ui_certificate"."name"') | ||
_info "Current WebUI certificate ID: $_ui_certificate_id" | ||
_info "Current WebUI certificate name: $_ui_certificate_name" | ||
|
||
########## Upload new certificate | ||
|
||
_info "Upload new certificate..." | ||
_certname="acme_$(_utc_date | tr -d '\-\:' | tr ' ' '_')" | ||
_debug _certname "$_certname" | ||
_ws_jobid=$(_ws_call "certificate.create" "{\"name\": \"${_certname}\", \"create_type\": \"CERTIFICATE_CREATE_IMPORTED\", \"certificate\": \"$(_json_encode <"$_file_fullchain")\", \"privatekey\": \"$(_json_encode <"$_file_key")\", \"passphrase\": \"\"}") | ||
_debug "_ws_jobid" "$_ws_jobid" | ||
if ! _ws_check_jobid "$_ws_jobid"; then | ||
_err "No JobID returned from websocket method." | ||
return 3 | ||
fi | ||
_ws_result=$(_ws_get_job_result "$_ws_jobid") | ||
_ws_ret=$? | ||
if [ $_ws_ret -gt 0 ]; then | ||
return $_ws_ret | ||
fi | ||
_debug "_ws_result" "$_ws_result" | ||
_new_certid=$(printf "%s" "$_ws_result" | jq -r '."id"') | ||
_info "New certificate ID: $_new_certid" | ||
|
||
########## FTP | ||
|
||
_info "Replace FTP certificate..." | ||
_ws_response=$(_ws_call "ftp.update" "{\"ssltls_certificate\": $_new_certid}") | ||
_ftp_certid=$(printf "%s" "$_ws_response" | jq -r '."ssltls_certificate"') | ||
if [ "$_ftp_certid" != "$_new_certid" ]; then | ||
_err "Cannot set FTP certificate." | ||
_debug "_ws_response" "$_ws_response" | ||
return 4 | ||
fi | ||
|
||
########## ix Apps (SCALE only) | ||
|
||
if [ "$_truenas_system" = "SCALE" ]; then | ||
_info "Replace app certificates..." | ||
_ws_response=$(_ws_call "app.query") | ||
for _app_name in $(printf "%s" "$_ws_response" | jq -r '.[]."name"'); do | ||
_info "Checking app $_app_name..." | ||
_ws_response=$(_ws_call "app.config" "$_app_name") | ||
if [ "$(printf "%s" "$_ws_response" | jq -r '."network" | has("certificate_id")')" = "true" ]; then | ||
_info "App has certificate option, setup new certificate..." | ||
_info "App will be redeployed after updating the certificate." | ||
_ws_jobid=$(_ws_call "app.update" "$_app_name" "{\"values\": {\"network\": {\"certificate_id\": $_new_certid}}}") | ||
_debug "_ws_jobid" "$_ws_jobid" | ||
if ! _ws_check_jobid "$_ws_jobid"; then | ||
_err "No JobID returned from websocket method." | ||
return 3 | ||
fi | ||
_ws_result=$(_ws_get_job_result "$_ws_jobid") | ||
_ws_ret=$? | ||
if [ $_ws_ret -gt 0 ]; then | ||
return $_ws_ret | ||
fi | ||
_debug "_ws_result" "$_ws_result" | ||
_info "App certificate replaced." | ||
else | ||
_info "App has no certificate option, skipping..." | ||
fi | ||
done | ||
fi | ||
|
||
########## WebUI | ||
|
||
_info "Replace WebUI certificate..." | ||
_ws_response=$(_ws_call "system.general.update" "{\"ui_certificate\": $_new_certid}") | ||
_changed_certid=$(printf "%s" "$_ws_response" | jq -r '."ui_certificate"."id"') | ||
if [ "$_changed_certid" != "$_new_certid" ]; then | ||
_err "WebUI certificate change error.." | ||
return 5 | ||
else | ||
_info "WebUI certificate replaced." | ||
fi | ||
_info "Restarting WebUI..." | ||
_ws_response=$(_ws_call "system.general.ui_restart") | ||
_info "Waiting for UI restart..." | ||
sleep 6 | ||
|
||
########## Certificates | ||
|
||
_info "Deleting old certificate..." | ||
_ws_jobid=$(_ws_call "certificate.delete" "$_ui_certificate_id") | ||
if ! _ws_check_jobid "$_ws_jobid"; then | ||
_err "No JobID returned from websocket method." | ||
return 3 | ||
fi | ||
_ws_result=$(_ws_get_job_result "$_ws_jobid") | ||
_ws_ret=$? | ||
if [ $_ws_ret -gt 0 ]; then | ||
return $_ws_ret | ||
fi | ||
|
||
_info "Have a nice day...bye!" | ||
|
||
} |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it's not bash. it's
sh
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done and tested
`*************************************
**** INSTALLING NEW CERTIFICATES ****
[Mon Nov 25 21:22:37 CET 2024] Checking environment variables...
[Mon Nov 25 21:22:37 CET 2024] Environment variables: OK
[Mon Nov 25 21:22:37 CET 2024] Checking TrueNAS health...
[Mon Nov 25 21:22:37 CET 2024] TrueNAS health: OK
[Mon Nov 25 21:22:37 CET 2024] Gather system info...
[Mon Nov 25 21:22:37 CET 2024] TrueNAS system: SCALE
[Mon Nov 25 21:22:37 CET 2024] TrueNAS version: 24.10.0.2
[Mon Nov 25 21:22:37 CET 2024] Gather current WebUI certificate...
[Mon Nov 25 21:22:37 CET 2024] Current WebUI certificate ID: 183
[Mon Nov 25 21:22:37 CET 2024] Current WebUI certificate name: acme_20241125_201715
[Mon Nov 25 21:22:37 CET 2024] Upload new certificate...
[Mon Nov 25 21:22:37 CET 2024] New WebUI certificate name: acme_20241125_202237
[Mon Nov 25 21:22:52 CET 2024] New certificate ID: 184
[Mon Nov 25 21:22:52 CET 2024] Replace FTP certificate...
[Mon Nov 25 21:22:53 CET 2024] Replace app certificates...
[Mon Nov 25 21:22:54 CET 2024] Checking app vaultwarden...
[Mon Nov 25 21:22:54 CET 2024] App has certificate option, setup new certificate...
[Mon Nov 25 21:22:54 CET 2024] App will be redeployed after updating the certificate.
[Mon Nov 25 21:23:07 CET 2024] App certificate replaced.
[Mon Nov 25 21:23:07 CET 2024] Checking app portainer...
[Mon Nov 25 21:23:07 CET 2024] App has certificate option, setup new certificate...
[Mon Nov 25 21:23:07 CET 2024] App will be redeployed after updating the certificate.
[Mon Nov 25 21:23:11 CET 2024] App certificate replaced.
[Mon Nov 25 21:23:11 CET 2024] Replace WebUI certificate...
[Mon Nov 25 21:23:14 CET 2024] WebUI certificate replaced.
[Mon Nov 25 21:23:14 CET 2024] Restarting WebUI...
[Mon Nov 25 21:23:14 CET 2024] Waiting for UI restart...
[Mon Nov 25 21:23:20 CET 2024] Deleting old certificate...
[Mon Nov 25 21:23:23 CET 2024] Have a nice day...bye!
[Mon Nov 25 21:23:23 CET 2024] Success
`