feat: add unfreeze_on_demand to remaining 35 SDKs
Updated awk, bash, clojure, cobol, cpp, crystal, csharp, dart, dotnet, d, elixir, erlang, fortran, fsharp, groovy, haskell, julia, kotlin, lisp, lua, nim, objective-c, ocaml, perl, php (sync+async), powershell, prolog, raku, r, scheme, swift, tcl, v, and zig SDKs: - Add set_unfreeze_on_demand function (PATCH /services/:id) - Add --unfreeze-on-demand flag for service creation - Add --set-unfreeze-on-demand command for existing services
This commit is contained in:
parent
e58adcd5fe
commit
7e56327056
35 changed files with 1047 additions and 104 deletions
|
|
@ -308,6 +308,40 @@ function service_resize(id, vcpu , endpoint, json, tmp, timestamp, sig_header
|
|||
print GREEN "Service resized to " vcpu " vCPU, " ram " GB RAM" RESET
|
||||
}
|
||||
|
||||
function set_unfreeze_on_demand(id, enabled , endpoint, json, tmp, timestamp, sig_headers, signature, sig_input, sig_cmd, enabled_str) {
|
||||
get_api_keys()
|
||||
endpoint = "/services/" id
|
||||
enabled_str = (enabled ? "true" : "false")
|
||||
json = "{\"unfreeze_on_demand\":" enabled_str "}"
|
||||
|
||||
# Write to temp file
|
||||
tmp = "/tmp/un_awk_unfreeze_" PROCINFO["pid"] ".json"
|
||||
print json > tmp
|
||||
close(tmp)
|
||||
|
||||
timestamp = systime()
|
||||
sig_headers = ""
|
||||
if (GLOBAL_SECRET_KEY != "") {
|
||||
sig_input = timestamp ":PATCH:" endpoint ":" json
|
||||
sig_cmd = "echo -n '" sig_input "' | openssl dgst -sha256 -hmac '" GLOBAL_SECRET_KEY "' | sed 's/^.* //'"
|
||||
sig_cmd | getline signature
|
||||
close(sig_cmd)
|
||||
sig_headers = "-H 'X-Timestamp: " timestamp "' -H 'X-Signature: " signature "' "
|
||||
}
|
||||
|
||||
cmd = "curl -s -X PATCH '" API_BASE endpoint "' " \
|
||||
"-H 'Content-Type: application/json' " \
|
||||
"-H 'Authorization: Bearer " GLOBAL_PUBLIC_KEY "' " \
|
||||
sig_headers \
|
||||
"-d '@" tmp "'"
|
||||
system(cmd " > /dev/null")
|
||||
|
||||
# Clean up
|
||||
system("rm -f " tmp)
|
||||
|
||||
print GREEN "Service unfreeze_on_demand set to " enabled_str RESET
|
||||
}
|
||||
|
||||
function service_dump_bootstrap(id, dump_file , endpoint, json_body, timestamp, sig_headers, signature, sig_input, sig_cmd) {
|
||||
get_api_keys()
|
||||
print "Fetching bootstrap script from " id "..." > "/dev/stderr"
|
||||
|
|
@ -445,7 +479,7 @@ function session_create(shell, network, vcpu, input_files , json, tmp, timest
|
|||
print response
|
||||
}
|
||||
|
||||
function service_create(name, ports, domains, service_type, bootstrap, bootstrap_file, input_files , json, tmp, timestamp, sig_headers, signature, sig_input, sig_cmd, boot_content, line, input_files_json, response) {
|
||||
function service_create(name, ports, domains, service_type, bootstrap, bootstrap_file, input_files, unfreeze_on_demand , json, tmp, timestamp, sig_headers, signature, sig_input, sig_cmd, boot_content, line, input_files_json, response) {
|
||||
get_api_keys()
|
||||
|
||||
# Build JSON payload
|
||||
|
|
@ -497,6 +531,11 @@ function service_create(name, ports, domains, service_type, bootstrap, bootstrap
|
|||
json = json input_files_json
|
||||
}
|
||||
|
||||
# Add unfreeze_on_demand if provided
|
||||
if (unfreeze_on_demand != "") {
|
||||
json = json ",\"unfreeze_on_demand\":" (unfreeze_on_demand ? "true" : "false")
|
||||
}
|
||||
|
||||
json = json "}"
|
||||
|
||||
# Write to temp file
|
||||
|
|
@ -1665,6 +1704,24 @@ END {
|
|||
exit 1
|
||||
}
|
||||
service_resize(resize_id, resize_vcpu)
|
||||
} else if (ARGC >= 4 && ARGV[2] == "--set-unfreeze-on-demand") {
|
||||
# Parse enabled flag
|
||||
set_uod_id = ARGV[3]
|
||||
set_uod_enabled = ""
|
||||
i = 4
|
||||
while (i < ARGC) {
|
||||
if (ARGV[i] == "--enabled" && i + 1 < ARGC) {
|
||||
set_uod_enabled = ARGV[i + 1]
|
||||
i += 2
|
||||
} else {
|
||||
i++
|
||||
}
|
||||
}
|
||||
if (set_uod_enabled == "") {
|
||||
print RED "Error: --enabled (true/false) is required with --set-unfreeze-on-demand" RESET > "/dev/stderr"
|
||||
exit 1
|
||||
}
|
||||
set_unfreeze_on_demand(set_uod_id, (set_uod_enabled == "true"))
|
||||
} else if (ARGC >= 4 && ARGV[2] == "--dump-bootstrap") {
|
||||
dump_file = ""
|
||||
if (ARGC >= 6 && ARGV[4] == "--dump-file") {
|
||||
|
|
|
|||
|
|
@ -131,6 +131,14 @@ run() {
|
|||
execute "$lang" "$code"
|
||||
}
|
||||
|
||||
# Service toggle functions
|
||||
set_unfreeze_on_demand() {
|
||||
local service_id="$1"
|
||||
local enabled="$2"
|
||||
local body="{\"unfreeze_on_demand\":$enabled}"
|
||||
api_request "PATCH" "/services/$service_id" "$body"
|
||||
}
|
||||
|
||||
# Job management
|
||||
get_job() {
|
||||
local job_id="$1"
|
||||
|
|
|
|||
|
|
@ -234,6 +234,12 @@
|
|||
(check-clock-drift-error out)
|
||||
out)))
|
||||
|
||||
(defn set-unfreeze-on-demand [service-id enabled]
|
||||
(let [api-key (get-api-key)
|
||||
json (str "{\"unfreeze_on_demand\":" (if enabled "true" "false") "}")]
|
||||
(curl-patch api-key (str "/services/" service-id) json)
|
||||
(println (str green "Service unfreeze_on_demand set to " (if enabled "true" "false") reset))))
|
||||
|
||||
(def max-env-content-size 65536)
|
||||
|
||||
(defn read-env-file [path]
|
||||
|
|
@ -397,7 +403,7 @@
|
|||
(println (str yellow "Session created (WebSocket required)" reset))
|
||||
(println (curl-post api-key "/sessions" json))))))
|
||||
|
||||
(defn service-command [action sid name ports bootstrap bootstrap-file service-type network vcpu input-files envs env-file]
|
||||
(defn service-command [action sid name ports bootstrap bootstrap-file service-type network vcpu input-files envs env-file unfreeze-on-demand]
|
||||
(let [api-key (get-api-key)]
|
||||
(case action
|
||||
:env (service-env-command sid name envs env-file)
|
||||
|
|
@ -423,6 +429,8 @@
|
|||
_ (curl-patch api-key (str "/services/" sid) json)
|
||||
ram (* vcpu 2)]
|
||||
(println (str green "Service resized to " vcpu " vCPU, " ram " GB RAM" reset)))))
|
||||
:set-unfreeze-on-demand (when sid
|
||||
(set-unfreeze-on-demand sid unfreeze-on-demand))
|
||||
:execute (when (and sid bootstrap)
|
||||
(let [json (str "{\"command\":\"" (escape-json bootstrap) "\"}")
|
||||
response (curl-post api-key (str "/services/" sid "/execute") json)
|
||||
|
|
@ -457,8 +465,9 @@
|
|||
service-type-json (if service-type (str ",\"service_type\":\"" service-type "\"") "")
|
||||
network-json (if network (str ",\"network\":\"" network "\"") "")
|
||||
vcpu-json (if vcpu (str ",\"vcpu\":" vcpu) "")
|
||||
unfreeze-on-demand-json (if (some? unfreeze-on-demand) (str ",\"unfreeze_on_demand\":" (if unfreeze-on-demand "true" "false")) "")
|
||||
input-files-json (build-input-files-json input-files)
|
||||
json (str "{\"name\":\"" name "\"" ports-json bootstrap-json bootstrap-content-json service-type-json network-json vcpu-json input-files-json "}")
|
||||
json (str "{\"name\":\"" name "\"" ports-json bootstrap-json bootstrap-content-json service-type-json network-json vcpu-json unfreeze-on-demand-json input-files-json "}")
|
||||
response (curl-post api-key "/services" json)
|
||||
service-id (extract-field "id" response)]
|
||||
(println (str green "Service created" reset))
|
||||
|
|
@ -665,6 +674,7 @@
|
|||
service-input-files []
|
||||
service-envs []
|
||||
service-env-file nil
|
||||
service-unfreeze-on-demand nil
|
||||
key-extend false
|
||||
image-action nil
|
||||
image-id nil
|
||||
|
|
@ -677,7 +687,7 @@
|
|||
(empty? args)
|
||||
(case mode
|
||||
:session (session-command (or session-action :create) session-id session-shell network vcpu session-input-files)
|
||||
:service (service-command (or service-action :create) service-id service-name service-ports service-bootstrap service-bootstrap-file service-type network vcpu service-input-files service-envs service-env-file)
|
||||
:service (service-command (or service-action :create) service-id service-name service-ports service-bootstrap service-bootstrap-file service-type network vcpu service-input-files service-envs service-env-file service-unfreeze-on-demand)
|
||||
:key (key-command key-extend)
|
||||
:languages (languages-command false)
|
||||
:image (image-command (or image-action :list) image-id image-source-type image-visibility image-name image-ports)
|
||||
|
|
@ -694,77 +704,77 @@
|
|||
|
||||
(= (first args) "session")
|
||||
(recur (rest args) file env-vars artifacts out-dir network vcpu session-action session-id session-shell session-input-files
|
||||
service-action service-id service-name service-ports service-bootstrap service-bootstrap-file service-type service-input-files service-envs service-env-file key-extend image-action image-id image-source-type image-visibility image-name image-ports :session)
|
||||
service-action service-id service-name service-ports service-bootstrap service-bootstrap-file service-type service-input-files service-envs service-env-file service-unfreeze-on-demand key-extend image-action image-id image-source-type image-visibility image-name image-ports :session)
|
||||
|
||||
(= (first args) "service")
|
||||
(recur (rest args) file env-vars artifacts out-dir network vcpu session-action session-id session-shell session-input-files
|
||||
service-action service-id service-name service-ports service-bootstrap service-bootstrap-file service-type service-input-files service-envs service-env-file key-extend image-action image-id image-source-type image-visibility image-name image-ports :service)
|
||||
service-action service-id service-name service-ports service-bootstrap service-bootstrap-file service-type service-input-files service-envs service-env-file service-unfreeze-on-demand key-extend image-action image-id image-source-type image-visibility image-name image-ports :service)
|
||||
|
||||
(= (first args) "key")
|
||||
(recur (rest args) file env-vars artifacts out-dir network vcpu session-action session-id session-shell session-input-files
|
||||
service-action service-id service-name service-ports service-bootstrap service-bootstrap-file service-type service-input-files service-envs service-env-file key-extend image-action image-id image-source-type image-visibility image-name image-ports :key)
|
||||
service-action service-id service-name service-ports service-bootstrap service-bootstrap-file service-type service-input-files service-envs service-env-file service-unfreeze-on-demand key-extend image-action image-id image-source-type image-visibility image-name image-ports :key)
|
||||
|
||||
(= (first args) "languages")
|
||||
(recur (rest args) file env-vars artifacts out-dir network vcpu session-action session-id session-shell session-input-files
|
||||
service-action service-id service-name service-ports service-bootstrap service-bootstrap-file service-type service-input-files service-envs service-env-file key-extend image-action image-id image-source-type image-visibility image-name image-ports :languages)
|
||||
service-action service-id service-name service-ports service-bootstrap service-bootstrap-file service-type service-input-files service-envs service-env-file service-unfreeze-on-demand key-extend image-action image-id image-source-type image-visibility image-name image-ports :languages)
|
||||
|
||||
(= (first args) "image")
|
||||
(recur (rest args) file env-vars artifacts out-dir network vcpu session-action session-id session-shell session-input-files
|
||||
service-action service-id service-name service-ports service-bootstrap service-bootstrap-file service-type service-input-files service-envs service-env-file key-extend image-action image-id image-source-type image-visibility image-name image-ports :image)
|
||||
service-action service-id service-name service-ports service-bootstrap service-bootstrap-file service-type service-input-files service-envs service-env-file service-unfreeze-on-demand key-extend image-action image-id image-source-type image-visibility image-name image-ports :image)
|
||||
|
||||
;; Image options
|
||||
(and (= mode :image) (or (= (first args) "--list") (= (first args) "-l")))
|
||||
(recur (rest args) file env-vars artifacts out-dir network vcpu session-action session-id session-shell session-input-files
|
||||
service-action service-id service-name service-ports service-bootstrap service-bootstrap-file service-type service-input-files service-envs service-env-file key-extend :list image-id image-source-type image-visibility image-name image-ports mode)
|
||||
service-action service-id service-name service-ports service-bootstrap service-bootstrap-file service-type service-input-files service-envs service-env-file service-unfreeze-on-demand key-extend :list image-id image-source-type image-visibility image-name image-ports mode)
|
||||
|
||||
(and (= mode :image) (= (first args) "--info"))
|
||||
(recur (rest (rest args)) file env-vars artifacts out-dir network vcpu session-action session-id session-shell session-input-files
|
||||
service-action service-id service-name service-ports service-bootstrap service-bootstrap-file service-type service-input-files service-envs service-env-file key-extend :info (second args) image-source-type image-visibility image-name image-ports mode)
|
||||
service-action service-id service-name service-ports service-bootstrap service-bootstrap-file service-type service-input-files service-envs service-env-file service-unfreeze-on-demand key-extend :info (second args) image-source-type image-visibility image-name image-ports mode)
|
||||
|
||||
(and (= mode :image) (= (first args) "--delete"))
|
||||
(recur (rest (rest args)) file env-vars artifacts out-dir network vcpu session-action session-id session-shell session-input-files
|
||||
service-action service-id service-name service-ports service-bootstrap service-bootstrap-file service-type service-input-files service-envs service-env-file key-extend :delete (second args) image-source-type image-visibility image-name image-ports mode)
|
||||
service-action service-id service-name service-ports service-bootstrap service-bootstrap-file service-type service-input-files service-envs service-env-file service-unfreeze-on-demand key-extend :delete (second args) image-source-type image-visibility image-name image-ports mode)
|
||||
|
||||
(and (= mode :image) (= (first args) "--lock"))
|
||||
(recur (rest (rest args)) file env-vars artifacts out-dir network vcpu session-action session-id session-shell session-input-files
|
||||
service-action service-id service-name service-ports service-bootstrap service-bootstrap-file service-type service-input-files service-envs service-env-file key-extend :lock (second args) image-source-type image-visibility image-name image-ports mode)
|
||||
service-action service-id service-name service-ports service-bootstrap service-bootstrap-file service-type service-input-files service-envs service-env-file service-unfreeze-on-demand key-extend :lock (second args) image-source-type image-visibility image-name image-ports mode)
|
||||
|
||||
(and (= mode :image) (= (first args) "--unlock"))
|
||||
(recur (rest (rest args)) file env-vars artifacts out-dir network vcpu session-action session-id session-shell session-input-files
|
||||
service-action service-id service-name service-ports service-bootstrap service-bootstrap-file service-type service-input-files service-envs service-env-file key-extend :unlock (second args) image-source-type image-visibility image-name image-ports mode)
|
||||
service-action service-id service-name service-ports service-bootstrap service-bootstrap-file service-type service-input-files service-envs service-env-file service-unfreeze-on-demand key-extend :unlock (second args) image-source-type image-visibility image-name image-ports mode)
|
||||
|
||||
(and (= mode :image) (= (first args) "--publish"))
|
||||
(recur (rest (rest args)) file env-vars artifacts out-dir network vcpu session-action session-id session-shell session-input-files
|
||||
service-action service-id service-name service-ports service-bootstrap service-bootstrap-file service-type service-input-files service-envs service-env-file key-extend :publish (second args) image-source-type image-visibility image-name image-ports mode)
|
||||
service-action service-id service-name service-ports service-bootstrap service-bootstrap-file service-type service-input-files service-envs service-env-file service-unfreeze-on-demand key-extend :publish (second args) image-source-type image-visibility image-name image-ports mode)
|
||||
|
||||
(and (= mode :image) (= (first args) "--source-type"))
|
||||
(recur (rest (rest args)) file env-vars artifacts out-dir network vcpu session-action session-id session-shell session-input-files
|
||||
service-action service-id service-name service-ports service-bootstrap service-bootstrap-file service-type service-input-files service-envs service-env-file key-extend image-action image-id (second args) image-visibility image-name image-ports mode)
|
||||
service-action service-id service-name service-ports service-bootstrap service-bootstrap-file service-type service-input-files service-envs service-env-file service-unfreeze-on-demand key-extend image-action image-id (second args) image-visibility image-name image-ports mode)
|
||||
|
||||
(and (= mode :image) (= (first args) "--visibility"))
|
||||
(recur (rest (rest (rest args))) file env-vars artifacts out-dir network vcpu session-action session-id session-shell session-input-files
|
||||
service-action service-id service-name service-ports service-bootstrap service-bootstrap-file service-type service-input-files service-envs service-env-file key-extend :visibility (second args) image-source-type (nth args 2) image-name image-ports mode)
|
||||
service-action service-id service-name service-ports service-bootstrap service-bootstrap-file service-type service-input-files service-envs service-env-file service-unfreeze-on-demand key-extend :visibility (second args) image-source-type (nth args 2) image-name image-ports mode)
|
||||
|
||||
(and (= mode :image) (= (first args) "--spawn"))
|
||||
(recur (rest (rest args)) file env-vars artifacts out-dir network vcpu session-action session-id session-shell session-input-files
|
||||
service-action service-id service-name service-ports service-bootstrap service-bootstrap-file service-type service-input-files service-envs service-env-file key-extend :spawn (second args) image-source-type image-visibility image-name image-ports mode)
|
||||
service-action service-id service-name service-ports service-bootstrap service-bootstrap-file service-type service-input-files service-envs service-env-file service-unfreeze-on-demand key-extend :spawn (second args) image-source-type image-visibility image-name image-ports mode)
|
||||
|
||||
(and (= mode :image) (= (first args) "--clone"))
|
||||
(recur (rest (rest args)) file env-vars artifacts out-dir network vcpu session-action session-id session-shell session-input-files
|
||||
service-action service-id service-name service-ports service-bootstrap service-bootstrap-file service-type service-input-files service-envs service-env-file key-extend :clone (second args) image-source-type image-visibility image-name image-ports mode)
|
||||
service-action service-id service-name service-ports service-bootstrap service-bootstrap-file service-type service-input-files service-envs service-env-file service-unfreeze-on-demand key-extend :clone (second args) image-source-type image-visibility image-name image-ports mode)
|
||||
|
||||
(and (= mode :image) (= (first args) "--name"))
|
||||
(recur (rest (rest args)) file env-vars artifacts out-dir network vcpu session-action session-id session-shell session-input-files
|
||||
service-action service-id service-name service-ports service-bootstrap service-bootstrap-file service-type service-input-files service-envs service-env-file key-extend image-action image-id image-source-type image-visibility (second args) image-ports mode)
|
||||
service-action service-id service-name service-ports service-bootstrap service-bootstrap-file service-type service-input-files service-envs service-env-file service-unfreeze-on-demand key-extend image-action image-id image-source-type image-visibility (second args) image-ports mode)
|
||||
|
||||
(and (= mode :image) (= (first args) "--ports"))
|
||||
(recur (rest (rest args)) file env-vars artifacts out-dir network vcpu session-action session-id session-shell session-input-files
|
||||
service-action service-id service-name service-ports service-bootstrap service-bootstrap-file service-type service-input-files service-envs service-env-file key-extend image-action image-id image-source-type image-visibility image-name (second args) mode)
|
||||
service-action service-id service-name service-ports service-bootstrap service-bootstrap-file service-type service-input-files service-envs service-env-file service-unfreeze-on-demand key-extend image-action image-id image-source-type image-visibility image-name (second args) mode)
|
||||
|
||||
;; Key options
|
||||
(and (= mode :key) (= (first args) "--extend"))
|
||||
(recur (rest args) file env-vars artifacts out-dir network vcpu session-action session-id session-shell session-input-files
|
||||
service-action service-id service-name service-ports service-bootstrap service-bootstrap-file service-type service-input-files service-envs service-env-file true image-action image-id image-source-type image-visibility image-name image-ports mode)
|
||||
service-action service-id service-name service-ports service-bootstrap service-bootstrap-file service-type service-input-files service-envs service-env-file service-unfreeze-on-demand true image-action image-id image-source-type image-visibility image-name image-ports mode)
|
||||
|
||||
;; Languages options
|
||||
(and (= mode :languages) (= (first args) "--json"))
|
||||
|
|
@ -775,126 +785,134 @@
|
|||
;; Session options
|
||||
(and (= mode :session) (= (first args) "--list"))
|
||||
(recur (rest args) file env-vars artifacts out-dir network vcpu :list session-id session-shell session-input-files
|
||||
service-action service-id service-name service-ports service-bootstrap service-bootstrap-file service-type service-input-files service-envs service-env-file key-extend image-action image-id image-source-type image-visibility image-name image-ports mode)
|
||||
service-action service-id service-name service-ports service-bootstrap service-bootstrap-file service-type service-input-files service-envs service-env-file service-unfreeze-on-demand key-extend image-action image-id image-source-type image-visibility image-name image-ports mode)
|
||||
|
||||
(and (= mode :session) (= (first args) "--kill"))
|
||||
(recur (rest (rest args)) file env-vars artifacts out-dir network vcpu :kill (second args) session-shell session-input-files
|
||||
service-action service-id service-name service-ports service-bootstrap service-bootstrap-file service-type service-input-files service-envs service-env-file key-extend image-action image-id image-source-type image-visibility image-name image-ports mode)
|
||||
service-action service-id service-name service-ports service-bootstrap service-bootstrap-file service-type service-input-files service-envs service-env-file service-unfreeze-on-demand key-extend image-action image-id image-source-type image-visibility image-name image-ports mode)
|
||||
|
||||
(and (= mode :session) (or (= (first args) "--shell") (= (first args) "-s")))
|
||||
(recur (rest (rest args)) file env-vars artifacts out-dir network vcpu session-action session-id (second args) session-input-files
|
||||
service-action service-id service-name service-ports service-bootstrap service-bootstrap-file service-type service-input-files service-envs service-env-file key-extend image-action image-id image-source-type image-visibility image-name image-ports mode)
|
||||
service-action service-id service-name service-ports service-bootstrap service-bootstrap-file service-type service-input-files service-envs service-env-file service-unfreeze-on-demand key-extend image-action image-id image-source-type image-visibility image-name image-ports mode)
|
||||
|
||||
(and (= mode :session) (= (first args) "-f"))
|
||||
(recur (rest (rest args)) file env-vars artifacts out-dir network vcpu session-action session-id session-shell (conj session-input-files (second args))
|
||||
service-action service-id service-name service-ports service-bootstrap service-bootstrap-file service-type service-input-files service-envs service-env-file key-extend image-action image-id image-source-type image-visibility image-name image-ports mode)
|
||||
service-action service-id service-name service-ports service-bootstrap service-bootstrap-file service-type service-input-files service-envs service-env-file service-unfreeze-on-demand key-extend image-action image-id image-source-type image-visibility image-name image-ports mode)
|
||||
|
||||
;; Service options
|
||||
(and (= mode :service) (= (first args) "--list"))
|
||||
(recur (rest args) file env-vars artifacts out-dir network vcpu session-action session-id session-shell session-input-files
|
||||
:list service-id service-name service-ports service-bootstrap service-bootstrap-file service-type service-input-files service-envs service-env-file key-extend image-action image-id image-source-type image-visibility image-name image-ports mode)
|
||||
:list service-id service-name service-ports service-bootstrap service-bootstrap-file service-type service-input-files service-envs service-env-file service-unfreeze-on-demand key-extend image-action image-id image-source-type image-visibility image-name image-ports mode)
|
||||
|
||||
(and (= mode :service) (= (first args) "--info"))
|
||||
(recur (rest (rest args)) file env-vars artifacts out-dir network vcpu session-action session-id session-shell session-input-files
|
||||
:info (second args) service-name service-ports service-bootstrap service-bootstrap-file service-type service-input-files service-envs service-env-file key-extend image-action image-id image-source-type image-visibility image-name image-ports mode)
|
||||
:info (second args) service-name service-ports service-bootstrap service-bootstrap-file service-type service-input-files service-envs service-env-file service-unfreeze-on-demand key-extend image-action image-id image-source-type image-visibility image-name image-ports mode)
|
||||
|
||||
(and (= mode :service) (= (first args) "--logs"))
|
||||
(recur (rest (rest args)) file env-vars artifacts out-dir network vcpu session-action session-id session-shell session-input-files
|
||||
:logs (second args) service-name service-ports service-bootstrap service-bootstrap-file service-type service-input-files service-envs service-env-file key-extend image-action image-id image-source-type image-visibility image-name image-ports mode)
|
||||
:logs (second args) service-name service-ports service-bootstrap service-bootstrap-file service-type service-input-files service-envs service-env-file service-unfreeze-on-demand key-extend image-action image-id image-source-type image-visibility image-name image-ports mode)
|
||||
|
||||
(and (= mode :service) (= (first args) "--freeze"))
|
||||
(recur (rest (rest args)) file env-vars artifacts out-dir network vcpu session-action session-id session-shell session-input-files
|
||||
:sleep (second args) service-name service-ports service-bootstrap service-bootstrap-file service-type service-input-files service-envs service-env-file key-extend image-action image-id image-source-type image-visibility image-name image-ports mode)
|
||||
:sleep (second args) service-name service-ports service-bootstrap service-bootstrap-file service-type service-input-files service-envs service-env-file service-unfreeze-on-demand key-extend image-action image-id image-source-type image-visibility image-name image-ports mode)
|
||||
|
||||
(and (= mode :service) (= (first args) "--unfreeze"))
|
||||
(recur (rest (rest args)) file env-vars artifacts out-dir network vcpu session-action session-id session-shell session-input-files
|
||||
:wake (second args) service-name service-ports service-bootstrap service-bootstrap-file service-type service-input-files service-envs service-env-file key-extend image-action image-id image-source-type image-visibility image-name image-ports mode)
|
||||
:wake (second args) service-name service-ports service-bootstrap service-bootstrap-file service-type service-input-files service-envs service-env-file service-unfreeze-on-demand key-extend image-action image-id image-source-type image-visibility image-name image-ports mode)
|
||||
|
||||
(and (= mode :service) (= (first args) "--destroy"))
|
||||
(recur (rest (rest args)) file env-vars artifacts out-dir network vcpu session-action session-id session-shell session-input-files
|
||||
:destroy (second args) service-name service-ports service-bootstrap service-bootstrap-file service-type service-input-files service-envs service-env-file key-extend image-action image-id image-source-type image-visibility image-name image-ports mode)
|
||||
:destroy (second args) service-name service-ports service-bootstrap service-bootstrap-file service-type service-input-files service-envs service-env-file service-unfreeze-on-demand key-extend image-action image-id image-source-type image-visibility image-name image-ports mode)
|
||||
|
||||
(and (= mode :service) (= (first args) "--resize"))
|
||||
(recur (rest (rest args)) file env-vars artifacts out-dir network vcpu session-action session-id session-shell session-input-files
|
||||
:resize (second args) service-name service-ports service-bootstrap service-bootstrap-file service-type service-input-files service-envs service-env-file key-extend image-action image-id image-source-type image-visibility image-name image-ports mode)
|
||||
:resize (second args) service-name service-ports service-bootstrap service-bootstrap-file service-type service-input-files service-envs service-env-file service-unfreeze-on-demand key-extend image-action image-id image-source-type image-visibility image-name image-ports mode)
|
||||
|
||||
(and (= mode :service) (= (first args) "--set-unfreeze-on-demand"))
|
||||
(recur (rest (rest (rest args))) file env-vars artifacts out-dir network vcpu session-action session-id session-shell session-input-files
|
||||
:set-unfreeze-on-demand (second args) service-name service-ports service-bootstrap service-bootstrap-file service-type service-input-files service-envs service-env-file (= (nth args 2) "true") key-extend image-action image-id image-source-type image-visibility image-name image-ports mode)
|
||||
|
||||
(and (= mode :service) (= (first args) "--execute"))
|
||||
(recur (rest (rest (rest args))) file env-vars artifacts out-dir network vcpu session-action session-id session-shell session-input-files
|
||||
:execute (second args) service-name service-ports (nth args 2) service-bootstrap-file service-type service-input-files service-envs service-env-file key-extend image-action image-id image-source-type image-visibility image-name image-ports mode)
|
||||
:execute (second args) service-name service-ports (nth args 2) service-bootstrap-file service-type service-input-files service-envs service-env-file service-unfreeze-on-demand key-extend image-action image-id image-source-type image-visibility image-name image-ports mode)
|
||||
|
||||
(and (= mode :service) (= (first args) "--dump-bootstrap") (>= (count args) 3) (not (.startsWith (nth args 2) "-")))
|
||||
(recur (rest (rest (rest args))) file env-vars artifacts out-dir network vcpu session-action session-id session-shell session-input-files
|
||||
:dump-bootstrap (second args) service-name service-ports service-bootstrap (nth args 2) service-type service-input-files service-envs service-env-file key-extend image-action image-id image-source-type image-visibility image-name image-ports mode)
|
||||
:dump-bootstrap (second args) service-name service-ports service-bootstrap (nth args 2) service-type service-input-files service-envs service-env-file service-unfreeze-on-demand key-extend image-action image-id image-source-type image-visibility image-name image-ports mode)
|
||||
|
||||
(and (= mode :service) (= (first args) "--dump-bootstrap"))
|
||||
(recur (rest (rest args)) file env-vars artifacts out-dir network vcpu session-action session-id session-shell session-input-files
|
||||
:dump-bootstrap (second args) service-name service-ports service-bootstrap service-bootstrap-file service-type service-input-files service-envs service-env-file key-extend image-action image-id image-source-type image-visibility image-name image-ports mode)
|
||||
:dump-bootstrap (second args) service-name service-ports service-bootstrap service-bootstrap-file service-type service-input-files service-envs service-env-file service-unfreeze-on-demand key-extend image-action image-id image-source-type image-visibility image-name image-ports mode)
|
||||
|
||||
(and (= mode :service) (= (first args) "--name"))
|
||||
(recur (rest (rest args)) file env-vars artifacts out-dir network vcpu session-action session-id session-shell session-input-files
|
||||
:create service-id (second args) service-ports service-bootstrap service-bootstrap-file service-type service-input-files service-envs service-env-file key-extend image-action image-id image-source-type image-visibility image-name image-ports mode)
|
||||
:create service-id (second args) service-ports service-bootstrap service-bootstrap-file service-type service-input-files service-envs service-env-file service-unfreeze-on-demand key-extend image-action image-id image-source-type image-visibility image-name image-ports mode)
|
||||
|
||||
(and (= mode :service) (= (first args) "--ports"))
|
||||
(recur (rest (rest args)) file env-vars artifacts out-dir network vcpu session-action session-id session-shell session-input-files
|
||||
service-action service-id service-name (second args) service-bootstrap service-bootstrap-file service-type service-input-files service-envs service-env-file key-extend image-action image-id image-source-type image-visibility image-name image-ports mode)
|
||||
service-action service-id service-name (second args) service-bootstrap service-bootstrap-file service-type service-input-files service-envs service-env-file service-unfreeze-on-demand key-extend image-action image-id image-source-type image-visibility image-name image-ports mode)
|
||||
|
||||
(and (= mode :service) (= (first args) "--bootstrap"))
|
||||
(recur (rest (rest args)) file env-vars artifacts out-dir network vcpu session-action session-id session-shell session-input-files
|
||||
service-action service-id service-name service-ports (second args) service-bootstrap-file service-type service-input-files service-envs service-env-file key-extend image-action image-id image-source-type image-visibility image-name image-ports mode)
|
||||
service-action service-id service-name service-ports (second args) service-bootstrap-file service-type service-input-files service-envs service-env-file service-unfreeze-on-demand key-extend image-action image-id image-source-type image-visibility image-name image-ports mode)
|
||||
|
||||
(and (= mode :service) (= (first args) "--bootstrap-file"))
|
||||
(recur (rest (rest args)) file env-vars artifacts out-dir network vcpu session-action session-id session-shell session-input-files
|
||||
service-action service-id service-name service-ports service-bootstrap (second args) service-type service-input-files service-envs service-env-file key-extend image-action image-id image-source-type image-visibility image-name image-ports mode)
|
||||
service-action service-id service-name service-ports service-bootstrap (second args) service-type service-input-files service-envs service-env-file service-unfreeze-on-demand key-extend image-action image-id image-source-type image-visibility image-name image-ports mode)
|
||||
|
||||
(and (= mode :service) (= (first args) "--type"))
|
||||
(recur (rest (rest args)) file env-vars artifacts out-dir network vcpu session-action session-id session-shell session-input-files
|
||||
service-action service-id service-name service-ports service-bootstrap service-bootstrap-file (second args) service-input-files service-envs service-env-file key-extend image-action image-id image-source-type image-visibility image-name image-ports mode)
|
||||
service-action service-id service-name service-ports service-bootstrap service-bootstrap-file (second args) service-input-files service-envs service-env-file service-unfreeze-on-demand key-extend image-action image-id image-source-type image-visibility image-name image-ports mode)
|
||||
|
||||
(and (= mode :service) (= (first args) "-f"))
|
||||
(recur (rest (rest args)) file env-vars artifacts out-dir network vcpu session-action session-id session-shell session-input-files
|
||||
service-action service-id service-name service-ports service-bootstrap service-bootstrap-file service-type (conj service-input-files (second args)) service-envs service-env-file key-extend image-action image-id image-source-type image-visibility image-name image-ports mode)
|
||||
service-action service-id service-name service-ports service-bootstrap service-bootstrap-file service-type (conj service-input-files (second args)) service-envs service-env-file service-unfreeze-on-demand key-extend image-action image-id image-source-type image-visibility image-name image-ports mode)
|
||||
|
||||
(and (= mode :service) (= (first args) "env") (>= (count args) 2))
|
||||
(let [env-action (second args)
|
||||
env-target (when (and (>= (count args) 3) (not (.startsWith (nth args 2) "-"))) (nth args 2))
|
||||
rest-args (if env-target (drop 3 args) (drop 2 args))]
|
||||
(recur rest-args file env-vars artifacts out-dir network vcpu session-action session-id session-shell session-input-files
|
||||
:env env-action env-target service-ports service-bootstrap service-bootstrap-file service-type service-input-files service-envs service-env-file key-extend image-action image-id image-source-type image-visibility image-name image-ports mode))
|
||||
:env env-action env-target service-ports service-bootstrap service-bootstrap-file service-type service-input-files service-envs service-env-file service-unfreeze-on-demand key-extend image-action image-id image-source-type image-visibility image-name image-ports mode))
|
||||
|
||||
(and (= mode :service) (= (first args) "-e"))
|
||||
(recur (rest (rest args)) file env-vars artifacts out-dir network vcpu session-action session-id session-shell session-input-files
|
||||
service-action service-id service-name service-ports service-bootstrap service-bootstrap-file service-type service-input-files (conj service-envs (second args)) service-env-file key-extend image-action image-id image-source-type image-visibility image-name image-ports mode)
|
||||
service-action service-id service-name service-ports service-bootstrap service-bootstrap-file service-type service-input-files (conj service-envs (second args)) service-env-file service-unfreeze-on-demand key-extend image-action image-id image-source-type image-visibility image-name image-ports mode)
|
||||
|
||||
(and (= mode :service) (= (first args) "--env-file"))
|
||||
(recur (rest (rest args)) file env-vars artifacts out-dir network vcpu session-action session-id session-shell session-input-files
|
||||
service-action service-id service-name service-ports service-bootstrap service-bootstrap-file service-type service-input-files service-envs (second args) key-extend image-action image-id image-source-type image-visibility image-name image-ports mode)
|
||||
service-action service-id service-name service-ports service-bootstrap service-bootstrap-file service-type service-input-files service-envs (second args) service-unfreeze-on-demand key-extend image-action image-id image-source-type image-visibility image-name image-ports mode)
|
||||
|
||||
(and (= mode :service) (= (first args) "--unfreeze-on-demand"))
|
||||
(recur (rest (rest args)) file env-vars artifacts out-dir network vcpu session-action session-id session-shell session-input-files
|
||||
service-action service-id service-name service-ports service-bootstrap service-bootstrap-file service-type service-input-files service-envs service-env-file (= (second args) "true") key-extend image-action image-id image-source-type image-visibility image-name image-ports mode)
|
||||
|
||||
;; Execute options
|
||||
(= (first args) "-e")
|
||||
(let [[k v] (str/split (second args) #"=" 2)]
|
||||
(recur (rest (rest args)) file (conj env-vars [k v]) artifacts out-dir network vcpu
|
||||
session-action session-id session-shell session-input-files service-action service-id service-name service-ports service-bootstrap service-bootstrap-file service-type service-input-files service-envs service-env-file key-extend image-action image-id image-source-type image-visibility image-name image-ports mode))
|
||||
session-action session-id session-shell session-input-files service-action service-id service-name service-ports service-bootstrap service-bootstrap-file service-type service-input-files service-envs service-env-file service-unfreeze-on-demand key-extend image-action image-id image-source-type image-visibility image-name image-ports mode))
|
||||
|
||||
(= (first args) "-a")
|
||||
(recur (rest args) file env-vars true out-dir network vcpu session-action session-id session-shell session-input-files
|
||||
service-action service-id service-name service-ports service-bootstrap service-bootstrap-file service-type service-input-files service-envs service-env-file key-extend image-action image-id image-source-type image-visibility image-name image-ports mode)
|
||||
service-action service-id service-name service-ports service-bootstrap service-bootstrap-file service-type service-input-files service-envs service-env-file service-unfreeze-on-demand key-extend image-action image-id image-source-type image-visibility image-name image-ports mode)
|
||||
|
||||
(= (first args) "-o")
|
||||
(recur (rest (rest args)) file env-vars artifacts (second args) network vcpu session-action session-id session-shell session-input-files
|
||||
service-action service-id service-name service-ports service-bootstrap service-bootstrap-file service-type service-input-files service-envs service-env-file key-extend image-action image-id image-source-type image-visibility image-name image-ports mode)
|
||||
service-action service-id service-name service-ports service-bootstrap service-bootstrap-file service-type service-input-files service-envs service-env-file service-unfreeze-on-demand key-extend image-action image-id image-source-type image-visibility image-name image-ports mode)
|
||||
|
||||
(= (first args) "-n")
|
||||
(recur (rest (rest args)) file env-vars artifacts out-dir (second args) vcpu session-action session-id session-shell session-input-files
|
||||
service-action service-id service-name service-ports service-bootstrap service-bootstrap-file service-type service-input-files service-envs service-env-file key-extend image-action image-id image-source-type image-visibility image-name image-ports mode)
|
||||
service-action service-id service-name service-ports service-bootstrap service-bootstrap-file service-type service-input-files service-envs service-env-file service-unfreeze-on-demand key-extend image-action image-id image-source-type image-visibility image-name image-ports mode)
|
||||
|
||||
(= (first args) "-v")
|
||||
(recur (rest (rest args)) file env-vars artifacts out-dir network (Integer/parseInt (second args)) session-action session-id session-shell session-input-files
|
||||
service-action service-id service-name service-ports service-bootstrap service-bootstrap-file service-type service-input-files service-envs service-env-file key-extend image-action image-id image-source-type image-visibility image-name image-ports mode)
|
||||
service-action service-id service-name service-ports service-bootstrap service-bootstrap-file service-type service-input-files service-envs service-env-file service-unfreeze-on-demand key-extend image-action image-id image-source-type image-visibility image-name image-ports mode)
|
||||
|
||||
;; Source file
|
||||
(and (= mode :execute) (not (.startsWith (first args) "-")) (nil? file))
|
||||
(recur (rest args) (first args) env-vars artifacts out-dir network vcpu session-action session-id session-shell session-input-files
|
||||
service-action service-id service-name service-ports service-bootstrap service-bootstrap-file service-type service-input-files service-envs service-env-file key-extend image-action image-id image-source-type image-visibility image-name image-ports mode)
|
||||
service-action service-id service-name service-ports service-bootstrap service-bootstrap-file service-type service-input-files service-envs service-env-file service-unfreeze-on-demand key-extend image-action image-id image-source-type image-visibility image-name image-ports mode)
|
||||
|
||||
;; Unknown option check
|
||||
(and (= mode :session) (.startsWith (first args) "-"))
|
||||
|
|
@ -906,6 +924,6 @@
|
|||
|
||||
:else
|
||||
(recur (rest args) file env-vars artifacts out-dir network vcpu session-action session-id session-shell session-input-files
|
||||
service-action service-id service-name service-ports service-bootstrap service-bootstrap-file service-type service-input-files service-envs service-env-file key-extend image-action image-id image-source-type image-visibility image-name image-ports mode))))
|
||||
service-action service-id service-name service-ports service-bootstrap service-bootstrap-file service-type service-input-files service-envs service-env-file service-unfreeze-on-demand key-extend image-action image-id image-source-type image-visibility image-name image-ports mode))))
|
||||
|
||||
(parse-args *command-line-args*)
|
||||
|
|
|
|||
|
|
@ -93,6 +93,8 @@
|
|||
01 WS-IMAGE-VISIBILITY PIC X(32).
|
||||
01 WS-ARG4 PIC X(256).
|
||||
01 WS-ARG5 PIC X(256).
|
||||
01 WS-UNFREEZE-ON-DEMAND PIC X(8).
|
||||
01 WS-UOD-ENABLED PIC X(8).
|
||||
|
||||
PROCEDURE DIVISION.
|
||||
MAIN-PROCEDURE.
|
||||
|
|
@ -267,6 +269,10 @@
|
|||
ACCEPT WS-ID FROM ARGUMENT-VALUE
|
||||
PERFORM PARSE-SERVICE-RESIZE-ARGS
|
||||
PERFORM SERVICE-RESIZE
|
||||
ELSE IF WS-ARG2 = "--set-unfreeze-on-demand"
|
||||
ACCEPT WS-ID FROM ARGUMENT-VALUE
|
||||
PERFORM PARSE-SERVICE-UOD-ARGS
|
||||
PERFORM SERVICE-SET-UNFREEZE-ON-DEMAND
|
||||
ELSE IF WS-ARG2 = "--name"
|
||||
ACCEPT WS-NAME FROM ARGUMENT-VALUE
|
||||
PERFORM PARSE-SERVICE-CREATE-ARGS
|
||||
|
|
@ -274,7 +280,8 @@
|
|||
ELSE
|
||||
DISPLAY "Error: Use --list, --info, --logs, "
|
||||
"--freeze, --unfreeze, --destroy, --dump-bootstrap, "
|
||||
"--resize, --name, or env" UPON SYSERR
|
||||
"--resize, --set-unfreeze-on-demand, --name, or env"
|
||||
UPON SYSERR
|
||||
MOVE 1 TO RETURN-CODE
|
||||
END-IF.
|
||||
|
||||
|
|
@ -597,6 +604,7 @@
|
|||
PARSE-SERVICE-CREATE-ARGS.
|
||||
* Parse remaining arguments for service creation
|
||||
* This is a simplified parser that looks for specific flags
|
||||
MOVE SPACES TO WS-UNFREEZE-ON-DEMAND.
|
||||
ACCEPT WS-ARG3 FROM ARGUMENT-VALUE.
|
||||
PERFORM UNTIL WS-ARG3 = SPACES
|
||||
IF WS-ARG3 = "--ports"
|
||||
|
|
@ -609,6 +617,8 @@
|
|||
ACCEPT WS-BOOTSTRAP FROM ARGUMENT-VALUE
|
||||
ELSE IF WS-ARG3 = "--bootstrap-file"
|
||||
ACCEPT WS-BOOTSTRAP-FILE FROM ARGUMENT-VALUE
|
||||
ELSE IF WS-ARG3 = "--unfreeze-on-demand"
|
||||
ACCEPT WS-UNFREEZE-ON-DEMAND FROM ARGUMENT-VALUE
|
||||
ELSE IF WS-ARG3 = "-e"
|
||||
ACCEPT WS-ARG3 FROM ARGUMENT-VALUE
|
||||
IF WS-SVC-ENVS NOT = SPACES
|
||||
|
|
@ -817,6 +827,15 @@
|
|||
END-STRING
|
||||
END-IF.
|
||||
|
||||
* Add unfreeze_on_demand if provided
|
||||
IF WS-UNFREEZE-ON-DEMAND NOT = SPACES
|
||||
STRING FUNCTION TRIM(WS-CURL-CMD)
|
||||
",\"unfreeze_on_demand\":"
|
||||
FUNCTION TRIM(WS-UNFREEZE-ON-DEMAND)
|
||||
DELIMITED BY SIZE INTO WS-CURL-CMD
|
||||
END-STRING
|
||||
END-IF.
|
||||
|
||||
* Close JSON body
|
||||
STRING FUNCTION TRIM(WS-CURL-CMD) "}'; "
|
||||
"TS=$(date +%s); "
|
||||
|
|
@ -1005,6 +1024,50 @@
|
|||
|
||||
CALL "SYSTEM" USING WS-CURL-CMD.
|
||||
|
||||
PARSE-SERVICE-UOD-ARGS.
|
||||
* Parse --enabled argument for unfreeze_on_demand
|
||||
MOVE SPACES TO WS-UOD-ENABLED.
|
||||
ACCEPT WS-ARG3 FROM ARGUMENT-VALUE.
|
||||
PERFORM UNTIL WS-ARG3 = SPACES
|
||||
IF WS-ARG3 = "--enabled"
|
||||
ACCEPT WS-UOD-ENABLED FROM ARGUMENT-VALUE
|
||||
END-IF
|
||||
ACCEPT WS-ARG3 FROM ARGUMENT-VALUE
|
||||
END-PERFORM.
|
||||
|
||||
SERVICE-SET-UNFREEZE-ON-DEMAND.
|
||||
* Validate enabled value
|
||||
IF WS-UOD-ENABLED NOT = "true" AND WS-UOD-ENABLED NOT = "false"
|
||||
DISPLAY "Error: --set-unfreeze-on-demand requires "
|
||||
"--enabled true|false" UPON SYSERR
|
||||
MOVE 1 TO RETURN-CODE
|
||||
STOP RUN
|
||||
END-IF.
|
||||
|
||||
* Build and execute set unfreeze_on_demand request with HMAC auth
|
||||
STRING "TS=$(date +%s); "
|
||||
"BODY='{\"unfreeze_on_demand\":"
|
||||
FUNCTION TRIM(WS-UOD-ENABLED) "}'; "
|
||||
"SIG=$(echo -n \"$TS:PATCH:/services/"
|
||||
FUNCTION TRIM(WS-ID)
|
||||
":$BODY\" | openssl dgst -sha256 -hmac '"
|
||||
FUNCTION TRIM(WS-SECRET-KEY)
|
||||
"' | cut -d' ' -f2); "
|
||||
"curl -s -X PATCH 'https://api.unsandbox.com/services/"
|
||||
FUNCTION TRIM(WS-ID)
|
||||
"' "
|
||||
"-H 'Content-Type: application/json' "
|
||||
"-H 'Authorization: Bearer " FUNCTION TRIM(WS-PUBLIC-KEY) "' "
|
||||
"-H 'X-Timestamp: '$TS "
|
||||
"-H 'X-Signature: '$SIG "
|
||||
"-d \"$BODY\" >/dev/null && "
|
||||
"echo -e '\x1b[32mService unfreeze_on_demand set to "
|
||||
FUNCTION TRIM(WS-UOD-ENABLED) "\x1b[0m'"
|
||||
DELIMITED BY SIZE INTO WS-CURL-CMD
|
||||
END-STRING.
|
||||
|
||||
CALL "SYSTEM" USING WS-CURL-CMD.
|
||||
|
||||
HANDLE-LANGUAGES.
|
||||
* Get API keys
|
||||
ACCEPT WS-PUBLIC-KEY FROM ENVIRONMENT "UNSANDBOX_PUBLIC_KEY".
|
||||
|
|
|
|||
|
|
@ -321,6 +321,19 @@ bool service_env_delete(const string& service_id, const string& public_key, cons
|
|||
return true;
|
||||
}
|
||||
|
||||
void set_unfreeze_on_demand(const string& service_id, bool enabled, const string& public_key, const string& secret_key) {
|
||||
string path = "/services/" + service_id;
|
||||
string enabled_str = enabled ? "true" : "false";
|
||||
string body = "{\"unfreeze_on_demand\":" + enabled_str + "}";
|
||||
string auth_headers = build_auth_headers("PATCH", path, body, public_key, secret_key);
|
||||
string cmd = "curl -s -X PATCH '" + API_BASE + path + "' "
|
||||
"-H 'Content-Type: application/json' "
|
||||
+ auth_headers + " "
|
||||
"-d '" + body + "'";
|
||||
exec_curl(cmd);
|
||||
cout << GREEN << "Service unfreeze_on_demand set to " << enabled_str << RESET << endl;
|
||||
}
|
||||
|
||||
void cmd_service_env(const string& action, const string& target, const vector<string>& envs, const string& env_file, const string& public_key, const string& secret_key) {
|
||||
if (action == "status") {
|
||||
if (target.empty()) {
|
||||
|
|
@ -529,7 +542,7 @@ void cmd_session(bool list, const string& kill, const string& shell, const strin
|
|||
cout << exec_curl(cmd) << endl;
|
||||
}
|
||||
|
||||
void cmd_service(const string& name, const string& ports, const string& type, const string& bootstrap, const string& bootstrap_file, const vector<string>& files, bool list, const string& info, const string& logs, const string& tail, const string& sleep, const string& wake, const string& destroy, const string& resize, const string& execute, const string& command, const string& dump_bootstrap, const string& dump_file, const string& network, int vcpu, const vector<string>& envs, const string& env_file, const string& env_action, const string& env_target, const string& public_key, const string& secret_key) {
|
||||
void cmd_service(const string& name, const string& ports, const string& type, const string& bootstrap, const string& bootstrap_file, const vector<string>& files, bool list, const string& info, const string& logs, const string& tail, const string& sleep, const string& wake, const string& destroy, const string& resize, const string& execute, const string& command, const string& dump_bootstrap, const string& dump_file, const string& network, int vcpu, const vector<string>& envs, const string& env_file, const string& env_action, const string& env_target, const string& set_unfreeze_on_demand_id, int set_unfreeze_on_demand_enabled, int unfreeze_on_demand, const string& public_key, const string& secret_key) {
|
||||
// Handle service env subcommand
|
||||
if (!env_action.empty()) {
|
||||
cmd_service_env(env_action, env_target, envs, env_file, public_key, secret_key);
|
||||
|
|
@ -605,6 +618,15 @@ void cmd_service(const string& name, const string& ports, const string& type, co
|
|||
return;
|
||||
}
|
||||
|
||||
if (!set_unfreeze_on_demand_id.empty()) {
|
||||
if (set_unfreeze_on_demand_enabled < 0) {
|
||||
cerr << RED << "Error: --set-unfreeze-on-demand requires --enabled true|false" << RESET << endl;
|
||||
exit(1);
|
||||
}
|
||||
set_unfreeze_on_demand(set_unfreeze_on_demand_id, set_unfreeze_on_demand_enabled == 1, public_key, secret_key);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!execute.empty()) {
|
||||
ostringstream json;
|
||||
json << "{\"command\":\"" << escape_json(command) << "\"}";
|
||||
|
|
@ -733,6 +755,7 @@ void cmd_service(const string& name, const string& ports, const string& type, co
|
|||
}
|
||||
if (!network.empty()) json << ",\"network\":\"" << network << "\"";
|
||||
if (vcpu > 0) json << ",\"vcpu\":" << vcpu;
|
||||
if (unfreeze_on_demand >= 0) json << ",\"unfreeze_on_demand\":" << (unfreeze_on_demand ? "true" : "false");
|
||||
json << "}";
|
||||
|
||||
cout << YELLOW << "Creating service..." << RESET << endl;
|
||||
|
|
@ -1111,6 +1134,9 @@ int main(int argc, char* argv[]) {
|
|||
vector<string> files;
|
||||
vector<string> envs;
|
||||
string env_file, env_action, env_target;
|
||||
string set_unfreeze_on_demand_id;
|
||||
int set_unfreeze_on_demand_enabled = -1; // -1 = not specified, 0 = false, 1 = true
|
||||
int unfreeze_on_demand = -1; // For service creation
|
||||
|
||||
for (int i = 2; i < argc; i++) {
|
||||
string arg = argv[i];
|
||||
|
|
@ -1145,10 +1171,19 @@ int main(int argc, char* argv[]) {
|
|||
else if (arg == "--dump-file" && i+1 < argc) dump_file = argv[++i];
|
||||
else if (arg == "-n" && i+1 < argc) network = argv[++i];
|
||||
else if (arg == "-v" && i+1 < argc) vcpu = stoi(argv[++i]);
|
||||
else if (arg == "--set-unfreeze-on-demand" && i+1 < argc) set_unfreeze_on_demand_id = argv[++i];
|
||||
else if (arg == "--enabled" && i+1 < argc) {
|
||||
string val = argv[++i];
|
||||
set_unfreeze_on_demand_enabled = (val == "true") ? 1 : 0;
|
||||
}
|
||||
else if (arg == "--unfreeze-on-demand" && i+1 < argc) {
|
||||
string val = argv[++i];
|
||||
unfreeze_on_demand = (val == "true") ? 1 : 0;
|
||||
}
|
||||
else if (arg == "-k" && i+1 < argc) public_key = argv[++i];
|
||||
}
|
||||
|
||||
cmd_service(name, ports, type, bootstrap, bootstrap_file, files, list, info, logs, tail, sleep, wake, destroy, resize, execute, command, dump_bootstrap, dump_file, network, vcpu, envs, env_file, env_action, env_target, public_key, secret_key);
|
||||
cmd_service(name, ports, type, bootstrap, bootstrap_file, files, list, info, logs, tail, sleep, wake, destroy, resize, execute, command, dump_bootstrap, dump_file, network, vcpu, envs, env_file, env_action, env_target, set_unfreeze_on_demand_id, set_unfreeze_on_demand_enabled, unfreeze_on_demand, public_key, secret_key);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -746,6 +746,15 @@ def cmd_service(args)
|
|||
return
|
||||
end
|
||||
|
||||
if unfreeze_on_demand_id = args[:unfreeze_on_demand]?.as?(String)
|
||||
enabled = args[:unfreeze_on_demand_enabled]?.as?(Bool) || true
|
||||
payload = JSON.parse({unfreeze_on_demand: enabled}.to_json)
|
||||
api_request("/services/#{unfreeze_on_demand_id}", public_key, secret_key, method: "PATCH", data: payload)
|
||||
status = enabled ? "enabled" : "disabled"
|
||||
puts "#{GREEN}Unfreeze-on-demand #{status} for service: #{unfreeze_on_demand_id}#{RESET}"
|
||||
return
|
||||
end
|
||||
|
||||
if destroy_id = args[:destroy]?.as?(String)
|
||||
api_request("/services/#{destroy_id}", public_key, secret_key, method: "DELETE")
|
||||
puts "#{GREEN}Service destroyed: #{destroy_id}#{RESET}"
|
||||
|
|
@ -839,6 +848,11 @@ def cmd_service(args)
|
|||
payload.as_h["network"] = JSON::Any.new(network)
|
||||
end
|
||||
|
||||
# Add unfreeze_on_demand
|
||||
if args[:create_unfreeze_on_demand]?.as?(Bool)
|
||||
payload.as_h["unfreeze_on_demand"] = JSON::Any.new(true)
|
||||
end
|
||||
|
||||
# Add input files
|
||||
if files = args[:files]?.as?(Array(String))
|
||||
input_files = [] of JSON::Any
|
||||
|
|
@ -908,6 +922,9 @@ def main
|
|||
dump_file: nil,
|
||||
resize: nil,
|
||||
vcpu: nil,
|
||||
unfreeze_on_demand: nil,
|
||||
unfreeze_on_demand_enabled: true,
|
||||
create_unfreeze_on_demand: false,
|
||||
name: nil,
|
||||
ports: nil,
|
||||
domains: nil,
|
||||
|
|
@ -952,6 +969,9 @@ def main
|
|||
opts.on("--logs=ID", "Get service logs") { |id| args[:logs] = id }
|
||||
opts.on("--freeze=ID", "Sleep service") { |id| args[:sleep] = id }
|
||||
opts.on("--unfreeze=ID", "Wake service") { |id| args[:wake] = id }
|
||||
opts.on("--unfreeze-on-demand=ID", "Set unfreeze-on-demand for service") { |id| args[:unfreeze_on_demand] = id }
|
||||
opts.on("--unfreeze-on-demand-enabled=BOOL", "Enable/disable unfreeze-on-demand (default: true)") { |b| args[:unfreeze_on_demand_enabled] = b.downcase == "true" }
|
||||
opts.on("--with-unfreeze-on-demand", "Enable unfreeze-on-demand when creating service") { args[:create_unfreeze_on_demand] = true }
|
||||
opts.on("--destroy=ID", "Destroy service") { |id| args[:destroy] = id }
|
||||
opts.on("--execute=ID", "Execute command in service") { |id| args[:execute] = id }
|
||||
opts.on("--command=CMD", "Command to execute (with --execute)") { |cmd| args[:command] = cmd }
|
||||
|
|
|
|||
|
|
@ -407,6 +407,18 @@ class Un
|
|||
return;
|
||||
}
|
||||
|
||||
if (args.ServiceUnfreezeOnDemand != null)
|
||||
{
|
||||
var payload = new Dictionary<string, object>
|
||||
{
|
||||
["unfreeze_on_demand"] = args.ServiceUnfreezeOnDemandEnabled
|
||||
};
|
||||
ApiRequest($"/services/{args.ServiceUnfreezeOnDemand}", "PATCH", payload, publicKey, secretKey);
|
||||
string status = args.ServiceUnfreezeOnDemandEnabled ? "enabled" : "disabled";
|
||||
Console.WriteLine($"{GREEN}Unfreeze-on-demand {status} for service: {args.ServiceUnfreezeOnDemand}{RESET}");
|
||||
return;
|
||||
}
|
||||
|
||||
if (args.ServiceDestroy != null)
|
||||
{
|
||||
ApiRequest($"/services/{args.ServiceDestroy}", "DELETE", null, publicKey, secretKey);
|
||||
|
|
@ -501,6 +513,10 @@ class Un
|
|||
{
|
||||
payload["vcpu"] = args.Vcpu;
|
||||
}
|
||||
if (args.ServiceCreateUnfreezeOnDemand)
|
||||
{
|
||||
payload["unfreeze_on_demand"] = true;
|
||||
}
|
||||
|
||||
var result = ApiRequest("/services", "POST", payload, publicKey, secretKey);
|
||||
string serviceId = result.ContainsKey("id") ? (string)result["id"] : null;
|
||||
|
|
@ -1145,6 +1161,9 @@ class Un
|
|||
public string ServiceCommand = null;
|
||||
public string ServiceDumpBootstrap = null;
|
||||
public string ServiceDumpFile = null;
|
||||
public string ServiceUnfreezeOnDemand = null;
|
||||
public bool ServiceUnfreezeOnDemandEnabled = true;
|
||||
public bool ServiceCreateUnfreezeOnDemand = false;
|
||||
public string EnvFile = null;
|
||||
public string EnvAction = null;
|
||||
public string EnvTarget = null;
|
||||
|
|
@ -1201,6 +1220,9 @@ class Un
|
|||
else if (arg == "--command") result.ServiceCommand = args[++i];
|
||||
else if (arg == "--dump-bootstrap") result.ServiceDumpBootstrap = args[++i];
|
||||
else if (arg == "--dump-file") result.ServiceDumpFile = args[++i];
|
||||
else if (arg == "--unfreeze-on-demand") result.ServiceUnfreezeOnDemand = args[++i];
|
||||
else if (arg == "--unfreeze-on-demand-enabled") result.ServiceUnfreezeOnDemandEnabled = args[++i].ToLower() == "true";
|
||||
else if (arg == "--with-unfreeze-on-demand") result.ServiceCreateUnfreezeOnDemand = true;
|
||||
else if (arg == "--extend") result.KeyExtend = true;
|
||||
else if (!arg.StartsWith("-")) result.SourceFile = arg;
|
||||
}
|
||||
|
|
@ -1240,6 +1262,9 @@ Service options:
|
|||
--tail ID Get last 9000 lines
|
||||
--freeze ID Freeze service
|
||||
--unfreeze ID Unfreeze service
|
||||
--unfreeze-on-demand ID Set unfreeze-on-demand for service
|
||||
--unfreeze-on-demand-enabled BOOL Enable/disable (default: true)
|
||||
--with-unfreeze-on-demand Enable unfreeze-on-demand when creating service
|
||||
--destroy ID Destroy service
|
||||
--execute ID Execute command in service
|
||||
--command CMD Command to execute (with --execute)
|
||||
|
|
|
|||
|
|
@ -458,7 +458,7 @@ void cmdSession(bool list, string kill, string shell, string network, int vcpu,
|
|||
writeln(execCurl(cmd));
|
||||
}
|
||||
|
||||
void cmdService(string name, string ports, string bootstrap, string bootstrapFile, string type, bool list, string info, string logs, string tail, string sleep, string wake, string destroy, string resize, int resizeVcpu, string execute, string command, string dumpBootstrap, string dumpFile, string network, int vcpu, string[] inputFiles, string[] svcEnvs, string svcEnvFile, string envAction, string envTarget, string publicKey, string secretKey) {
|
||||
void cmdService(string name, string ports, string bootstrap, string bootstrapFile, string type, bool list, string info, string logs, string tail, string sleep, string wake, string destroy, string resize, int resizeVcpu, string execute, string command, string dumpBootstrap, string dumpFile, string unfreezeOnDemand, bool unfreezeOnDemandEnabled, bool createUnfreezeOnDemand, string network, int vcpu, string[] inputFiles, string[] svcEnvs, string svcEnvFile, string envAction, string envTarget, string publicKey, string secretKey) {
|
||||
// Handle env subcommand
|
||||
if (!envAction.empty) {
|
||||
cmdServiceEnv(envAction, envTarget, svcEnvs, svcEnvFile, publicKey, secretKey);
|
||||
|
|
@ -514,6 +514,17 @@ void cmdService(string name, string ports, string bootstrap, string bootstrapFil
|
|||
return;
|
||||
}
|
||||
|
||||
if (!unfreezeOnDemand.empty) {
|
||||
string json = format(`{"unfreeze_on_demand":%s}`, unfreezeOnDemandEnabled ? "true" : "false");
|
||||
string path = format("/services/%s", unfreezeOnDemand);
|
||||
string authHeaders = buildAuthHeaders("PATCH", path, json, publicKey, secretKey);
|
||||
string cmd = format(`curl -s -X PATCH '%s/services/%s' -H 'Content-Type: application/json' %s -d '%s'`, API_BASE, unfreezeOnDemand, authHeaders, json);
|
||||
execCurl(cmd);
|
||||
string status = unfreezeOnDemandEnabled ? "enabled" : "disabled";
|
||||
writefln("%sUnfreeze-on-demand %s for service: %s%s", GREEN, status, unfreezeOnDemand, RESET);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!destroy.empty) {
|
||||
string path = format("/services/%s", destroy);
|
||||
string authHeaders = buildAuthHeaders("DELETE", path, "", publicKey, secretKey);
|
||||
|
|
@ -629,6 +640,7 @@ void cmdService(string name, string ports, string bootstrap, string bootstrapFil
|
|||
}
|
||||
if (!network.empty) json ~= format(`,"network":"%s"`, network);
|
||||
if (vcpu > 0) json ~= format(`,"vcpu":%d`, vcpu);
|
||||
if (createUnfreezeOnDemand) json ~= `,"unfreeze_on_demand":true`;
|
||||
json ~= buildInputFilesJson(inputFiles);
|
||||
json ~= "}";
|
||||
|
||||
|
|
@ -999,7 +1011,9 @@ int main(string[] args) {
|
|||
if (args[1] == "service") {
|
||||
string name, ports, bootstrap, bootstrapFile, type;
|
||||
bool list = false;
|
||||
string info, logs, tail, sleep, wake, destroy, resize, execute, command, dumpBootstrap, dumpFile, network;
|
||||
string info, logs, tail, sleep, wake, destroy, resize, execute, command, dumpBootstrap, dumpFile, unfreezeOnDemand, network;
|
||||
bool unfreezeOnDemandEnabled = true;
|
||||
bool createUnfreezeOnDemand = false;
|
||||
int vcpu = 0;
|
||||
int resizeVcpu = 0;
|
||||
string[] inputFiles;
|
||||
|
|
@ -1016,7 +1030,7 @@ int main(string[] args) {
|
|||
else if (args[i] == "--env-file" && i+1 < args.length) svcEnvFile = args[++i];
|
||||
else if (args[i] == "-k" && i+1 < args.length) publicKey = args[++i];
|
||||
}
|
||||
cmdService(name, ports, bootstrap, bootstrapFile, type, list, info, logs, tail, sleep, wake, destroy, resize, resizeVcpu, execute, command, dumpBootstrap, dumpFile, network, vcpu, inputFiles, svcEnvs, svcEnvFile, envAction, envTarget, publicKey, secretKey);
|
||||
cmdService(name, ports, bootstrap, bootstrapFile, type, list, info, logs, tail, sleep, wake, destroy, resize, resizeVcpu, execute, command, dumpBootstrap, dumpFile, unfreezeOnDemand, unfreezeOnDemandEnabled, createUnfreezeOnDemand, network, vcpu, inputFiles, svcEnvs, svcEnvFile, envAction, envTarget, publicKey, secretKey);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -1039,6 +1053,9 @@ int main(string[] args) {
|
|||
else if (args[i] == "--command" && i+1 < args.length) command = args[++i];
|
||||
else if (args[i] == "--dump-bootstrap" && i+1 < args.length) dumpBootstrap = args[++i];
|
||||
else if (args[i] == "--dump-file" && i+1 < args.length) dumpFile = args[++i];
|
||||
else if (args[i] == "--unfreeze-on-demand" && i+1 < args.length) unfreezeOnDemand = args[++i];
|
||||
else if (args[i] == "--unfreeze-on-demand-enabled" && i+1 < args.length) unfreezeOnDemandEnabled = args[++i] == "true";
|
||||
else if (args[i] == "--with-unfreeze-on-demand") createUnfreezeOnDemand = true;
|
||||
else if (args[i] == "-n" && i+1 < args.length) network = args[++i];
|
||||
else if (args[i] == "-v" && i+1 < args.length) vcpu = to!int(args[++i]);
|
||||
else if (args[i] == "-f" && i+1 < args.length) inputFiles ~= args[++i];
|
||||
|
|
@ -1047,7 +1064,7 @@ int main(string[] args) {
|
|||
else if (args[i] == "-k" && i+1 < args.length) publicKey = args[++i];
|
||||
}
|
||||
|
||||
cmdService(name, ports, bootstrap, bootstrapFile, type, list, info, logs, tail, sleep, wake, destroy, resize, resizeVcpu, execute, command, dumpBootstrap, dumpFile, network, vcpu, inputFiles, svcEnvs, svcEnvFile, envAction, envTarget, publicKey, secretKey);
|
||||
cmdService(name, ports, bootstrap, bootstrapFile, type, list, info, logs, tail, sleep, wake, destroy, resize, resizeVcpu, execute, command, dumpBootstrap, dumpFile, unfreezeOnDemand, unfreezeOnDemandEnabled, createUnfreezeOnDemand, network, vcpu, inputFiles, svcEnvs, svcEnvFile, envAction, envTarget, publicKey, secretKey);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -101,6 +101,9 @@ class Args {
|
|||
String? serviceCommand;
|
||||
String? serviceDumpBootstrap;
|
||||
String? serviceDumpFile;
|
||||
String? serviceUnfreezeOnDemand;
|
||||
bool serviceUnfreezeOnDemandEnabled = true;
|
||||
bool serviceCreateUnfreezeOnDemand = false;
|
||||
bool keyExtend = false;
|
||||
String? envFile;
|
||||
String? envAction;
|
||||
|
|
@ -646,6 +649,14 @@ Future<void> cmdService(Args args) async {
|
|||
return;
|
||||
}
|
||||
|
||||
if (args.serviceUnfreezeOnDemand != null) {
|
||||
final payload = {'unfreeze_on_demand': args.serviceUnfreezeOnDemandEnabled};
|
||||
await apiRequestCurl('/services/${args.serviceUnfreezeOnDemand}', 'PATCH', jsonEncode(payload), publicKey, secretKey);
|
||||
final status = args.serviceUnfreezeOnDemandEnabled ? 'enabled' : 'disabled';
|
||||
print('${green}Unfreeze-on-demand $status for service: ${args.serviceUnfreezeOnDemand}$reset');
|
||||
return;
|
||||
}
|
||||
|
||||
if (args.serviceDestroy != null) {
|
||||
await apiRequestCurl('/services/${args.serviceDestroy}', 'DELETE', null, publicKey, secretKey);
|
||||
print('${green}Service destroyed: ${args.serviceDestroy}$reset');
|
||||
|
|
@ -736,6 +747,9 @@ Future<void> cmdService(Args args) async {
|
|||
if (args.vcpu > 0) {
|
||||
payload['vcpu'] = args.vcpu;
|
||||
}
|
||||
if (args.serviceCreateUnfreezeOnDemand) {
|
||||
payload['unfreeze_on_demand'] = true;
|
||||
}
|
||||
|
||||
// Add input files
|
||||
if (args.files.isNotEmpty) {
|
||||
|
|
@ -1091,6 +1105,15 @@ Args parseArgs(List<String> argv) {
|
|||
case '--dump-file':
|
||||
args.serviceDumpFile = argv[++i];
|
||||
break;
|
||||
case '--unfreeze-on-demand':
|
||||
args.serviceUnfreezeOnDemand = argv[++i];
|
||||
break;
|
||||
case '--unfreeze-on-demand-enabled':
|
||||
args.serviceUnfreezeOnDemandEnabled = argv[++i].toLowerCase() == 'true';
|
||||
break;
|
||||
case '--with-unfreeze-on-demand':
|
||||
args.serviceCreateUnfreezeOnDemand = true;
|
||||
break;
|
||||
case '--extend':
|
||||
args.keyExtend = true;
|
||||
break;
|
||||
|
|
@ -1202,6 +1225,9 @@ Service options:
|
|||
--tail ID Get last 9000 lines
|
||||
--freeze ID Freeze service
|
||||
--unfreeze ID Unfreeze service
|
||||
--unfreeze-on-demand ID Set unfreeze-on-demand for service
|
||||
--unfreeze-on-demand-enabled BOOL Enable/disable (default: true)
|
||||
--with-unfreeze-on-demand Enable unfreeze-on-demand when creating service
|
||||
--destroy ID Destroy service
|
||||
--execute ID Execute command in service
|
||||
--command CMD Command to execute (with --execute)
|
||||
|
|
|
|||
|
|
@ -299,6 +299,15 @@ async Task CmdServiceAsync(Args args)
|
|||
return;
|
||||
}
|
||||
|
||||
if (args.ServiceUnfreezeOnDemand != null)
|
||||
{
|
||||
var payload = new Dictionary<string, object> { ["unfreeze_on_demand"] = args.ServiceUnfreezeOnDemandEnabled };
|
||||
await ApiRequestAsync($"/services/{args.ServiceUnfreezeOnDemand}", new HttpMethod("PATCH"), payload, publicKey, secretKey);
|
||||
string status = args.ServiceUnfreezeOnDemandEnabled ? "enabled" : "disabled";
|
||||
Console.WriteLine($"{GREEN}Unfreeze-on-demand {status} for service: {args.ServiceUnfreezeOnDemand}{RESET}");
|
||||
return;
|
||||
}
|
||||
|
||||
if (args.ServiceDestroy != null)
|
||||
{
|
||||
await ApiRequestAsync($"/services/{args.ServiceDestroy}", HttpMethod.Delete, null, publicKey, secretKey);
|
||||
|
|
@ -347,6 +356,7 @@ async Task CmdServiceAsync(Args args)
|
|||
if (args.ServiceBootstrap != null) payload["bootstrap"] = args.ServiceBootstrap;
|
||||
if (args.Network != null) payload["network"] = args.Network;
|
||||
if (args.Vcpu > 0) payload["vcpu"] = args.Vcpu;
|
||||
if (args.ServiceCreateUnfreezeOnDemand) payload["unfreeze_on_demand"] = true;
|
||||
|
||||
var result = await ApiRequestAsync("/services", HttpMethod.Post, payload, publicKey, secretKey);
|
||||
var serviceId = result.TryGetValue("id", out var id) && id is JsonElement idEl ? idEl.GetString() : null;
|
||||
|
|
@ -568,6 +578,9 @@ Args ParseArgs(string[] args)
|
|||
else if (arg == "--command") result.ServiceCommand = args[++i];
|
||||
else if (arg == "--dump-bootstrap") result.ServiceDumpBootstrap = args[++i];
|
||||
else if (arg == "--dump-file") result.ServiceDumpFile = args[++i];
|
||||
else if (arg == "--unfreeze-on-demand") result.ServiceUnfreezeOnDemand = args[++i];
|
||||
else if (arg == "--unfreeze-on-demand-enabled") result.ServiceUnfreezeOnDemandEnabled = args[++i].ToLower() == "true";
|
||||
else if (arg == "--with-unfreeze-on-demand") result.ServiceCreateUnfreezeOnDemand = true;
|
||||
else if (arg == "--extend") result.KeyExtend = true;
|
||||
else if (!arg.StartsWith("-")) result.SourceFile = arg;
|
||||
}
|
||||
|
|
@ -609,6 +622,9 @@ Service options:
|
|||
--tail ID Get last 9000 lines
|
||||
--freeze ID Freeze service
|
||||
--unfreeze ID Unfreeze service
|
||||
--unfreeze-on-demand ID Set unfreeze-on-demand for service
|
||||
--unfreeze-on-demand-enabled BOOL Enable/disable (default: true)
|
||||
--with-unfreeze-on-demand Enable unfreeze-on-demand when creating service
|
||||
--destroy ID Destroy service
|
||||
--execute ID Execute command in service
|
||||
--command CMD Command to execute (with --execute)
|
||||
|
|
@ -643,6 +659,9 @@ class Args
|
|||
public string? ServiceInfo, ServiceLogs, ServiceTail, ServiceSleep, ServiceWake, ServiceDestroy;
|
||||
public string? ServiceExecute, ServiceCommand;
|
||||
public string? ServiceDumpBootstrap, ServiceDumpFile;
|
||||
public string? ServiceUnfreezeOnDemand;
|
||||
public bool ServiceUnfreezeOnDemandEnabled = true;
|
||||
public bool ServiceCreateUnfreezeOnDemand;
|
||||
public string? EnvFile, EnvAction, EnvTarget;
|
||||
public bool KeyExtend;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -96,6 +96,7 @@ defmodule Un do
|
|||
IO.puts(" un.ex languages [--json]")
|
||||
IO.puts("")
|
||||
IO.puts("Service options: --name, --ports, --bootstrap, -e KEY=VALUE, --env-file FILE")
|
||||
IO.puts(" --set-unfreeze-on-demand ID true|false")
|
||||
IO.puts("Service env commands: status, set, export, delete")
|
||||
IO.puts("Image options: --list, --info ID, --delete ID, --lock ID, --unlock ID,")
|
||||
IO.puts(" --publish ID --source-type TYPE, --visibility ID MODE,")
|
||||
|
|
@ -265,6 +266,14 @@ defmodule Un do
|
|||
IO.puts("#{@green}Service resized to #{vcpu_int} vCPU, #{ram} GB RAM#{@reset}")
|
||||
end
|
||||
|
||||
defp service_command(["--set-unfreeze-on-demand", service_id, enabled | _]) do
|
||||
api_key = get_api_key()
|
||||
enabled_bool = String.downcase(enabled) in ["true", "1", "yes", "on"]
|
||||
json = "{\"unfreeze_on_demand\":#{enabled_bool}}"
|
||||
curl_patch(api_key, "/services/#{service_id}", json)
|
||||
IO.puts("#{@green}Service unfreeze_on_demand set to #{enabled_bool}: #{service_id}#{@reset}")
|
||||
end
|
||||
|
||||
defp service_command(["--snapshot", service_id | rest]) do
|
||||
api_key = get_api_key()
|
||||
name = get_opt(rest, "--snapshot-name", nil, nil)
|
||||
|
|
|
|||
|
|
@ -227,6 +227,9 @@ service_command(["--resize", ServiceId, "--vcpu", VcpuStr | _]) ->
|
|||
service_command(["--resize", ServiceId, "-v", VcpuStr | _]) ->
|
||||
service_resize(ServiceId, VcpuStr);
|
||||
|
||||
service_command(["--set-unfreeze-on-demand", ServiceId, EnabledStr | _]) ->
|
||||
service_set_unfreeze_on_demand(ServiceId, EnabledStr);
|
||||
|
||||
service_command(["--execute", ServiceId, "--command", Command | _]) ->
|
||||
ApiKey = get_api_key(),
|
||||
Json = "{\"command\":\"" ++ escape_json(Command) ++ "\"}",
|
||||
|
|
@ -1002,6 +1005,21 @@ service_resize(ServiceId, VcpuStr) ->
|
|||
Ram = Vcpu * 2,
|
||||
io:format("\033[32mService resized to ~B vCPU, ~B GB RAM\033[0m~n", [Vcpu, Ram]).
|
||||
|
||||
service_set_unfreeze_on_demand(ServiceId, EnabledStr) ->
|
||||
ApiKey = get_api_key(),
|
||||
Enabled = case string:lowercase(EnabledStr) of
|
||||
"true" -> "true";
|
||||
"1" -> "true";
|
||||
"yes" -> "true";
|
||||
"on" -> "true";
|
||||
_ -> "false"
|
||||
end,
|
||||
Json = "{\"unfreeze_on_demand\":" ++ Enabled ++ "}",
|
||||
TmpFile = write_temp_file(Json),
|
||||
_ = curl_patch(ApiKey, "/services/" ++ ServiceId, TmpFile),
|
||||
file:delete(TmpFile),
|
||||
io:format("\033[32mService unfreeze_on_demand set to ~s: ~s\033[0m~n", [Enabled, ServiceId]).
|
||||
|
||||
%% Argument parsing
|
||||
parse_exec_args([], Opts) ->
|
||||
{maps:get(file, Opts), Opts};
|
||||
|
|
|
|||
|
|
@ -1257,6 +1257,16 @@ contains
|
|||
call get_command_argument(i+1, service_type)
|
||||
i = i + 1
|
||||
end if
|
||||
else if (trim(arg) == '--set-unfreeze-on-demand') then
|
||||
operation = 'set-unfreeze-on-demand'
|
||||
if (i+1 <= command_argument_count()) then
|
||||
call get_command_argument(i+1, service_id)
|
||||
i = i + 1
|
||||
end if
|
||||
if (i+1 <= command_argument_count()) then
|
||||
call get_command_argument(i+1, service_type)
|
||||
i = i + 1
|
||||
end if
|
||||
end if
|
||||
i = i + 1
|
||||
end do
|
||||
|
|
@ -1422,6 +1432,23 @@ contains
|
|||
'-d "$BODY" >/dev/null && ', &
|
||||
'echo -e "\x1b[32mService resized to ', resize_vcpu, ' vCPU, ', resize_vcpu * 2, ' GB RAM\x1b[0m"'
|
||||
call execute_command_line(trim(full_cmd), wait=.true.)
|
||||
else if (trim(operation) == 'set-unfreeze-on-demand' .and. len_trim(service_id) > 0) then
|
||||
! service_type holds the enabled value (true/false/1/0/yes/no/on/off)
|
||||
write(full_cmd, '(30A)') &
|
||||
'ENABLED_STR=$(echo "', trim(service_type), '" | tr "[:upper:]" "[:lower:]"); ', &
|
||||
'case "$ENABLED_STR" in true|1|yes|on) ENABLED=true;; *) ENABLED=false;; esac; ', &
|
||||
'BODY="{\"unfreeze_on_demand\":$ENABLED}"; ', &
|
||||
'TS=$(date +%s); ', &
|
||||
'SIG=$(echo -n "$TS:PATCH:/services/', trim(service_id), ':$BODY" | openssl dgst -sha256 -hmac "', trim(secret_key), '" | cut -d" " -f2); ', &
|
||||
'curl -s -X PATCH https://api.unsandbox.com/services/', &
|
||||
trim(service_id), ' ', &
|
||||
'-H "Content-Type: application/json" ', &
|
||||
'-H "Authorization: Bearer ', trim(public_key), '" ', &
|
||||
'-H "X-Timestamp: $TS" ', &
|
||||
'-H "X-Signature: $SIG" ', &
|
||||
'-d "$BODY" >/dev/null && ', &
|
||||
'echo -e "\x1b[32mService unfreeze_on_demand set to $ENABLED: ', trim(service_id), '\x1b[0m"'
|
||||
call execute_command_line(trim(full_cmd), wait=.true.)
|
||||
else if (trim(operation) == 'dump-bootstrap' .and. len_trim(service_id) > 0) then
|
||||
write(full_cmd, '(30A)') &
|
||||
'echo "Fetching bootstrap script from ', trim(service_id), '..." >&2; ', &
|
||||
|
|
@ -1480,7 +1507,7 @@ contains
|
|||
'else echo "$RESP" | jq .; fi'
|
||||
call execute_command_line(trim(full_cmd), wait=.true.)
|
||||
else
|
||||
write(0, '(A)') 'Error: Use --list, --info, --logs, --freeze, --unfreeze, --destroy, --dump-bootstrap, --name, or env'
|
||||
write(0, '(A)') 'Error: Use --list, --info, --logs, --freeze, --unfreeze, --destroy, --set-unfreeze-on-demand, --dump-bootstrap, --name, or env'
|
||||
stop 1
|
||||
end if
|
||||
end subroutine handle_service
|
||||
|
|
|
|||
|
|
@ -109,6 +109,8 @@ type Args = {
|
|||
mutable ServiceDumpBootstrap: string option
|
||||
mutable ServiceDumpFile: string option
|
||||
mutable ServiceResize: string option
|
||||
mutable ServiceSetUnfreezeOnDemand: string option
|
||||
mutable ServiceUnfreezeOnDemandValue: string option
|
||||
mutable ServiceSnapshot: string option
|
||||
mutable ServiceRestore: string option
|
||||
mutable ServiceFrom: string option
|
||||
|
|
@ -962,6 +964,12 @@ let cmdService (args: Args) =
|
|||
let result = apiRequestPatch (sprintf "/services/%s" args.ServiceResize.Value) payload publicKey secretKey
|
||||
let ram = args.Vcpu * 2
|
||||
printfn "%sService resized to %d vCPU, %d GB RAM%s" green args.Vcpu ram reset
|
||||
elif args.ServiceSetUnfreezeOnDemand.IsSome then
|
||||
let enabledStr = args.ServiceUnfreezeOnDemandValue.Value.ToLower()
|
||||
let enabled = enabledStr = "true" || enabledStr = "1" || enabledStr = "yes" || enabledStr = "on"
|
||||
let payload = [("unfreeze_on_demand", box enabled)]
|
||||
let result = apiRequestPatch (sprintf "/services/%s" args.ServiceSetUnfreezeOnDemand.Value) payload publicKey secretKey
|
||||
printfn "%sService unfreeze_on_demand set to %b: %s%s" green enabled args.ServiceSetUnfreezeOnDemand.Value reset
|
||||
elif args.ServiceExecute.IsSome then
|
||||
let payload = [("command", box args.ServiceCommand.Value)]
|
||||
let result = apiRequest (sprintf "/services/%s/execute" args.ServiceExecute.Value) "POST" (Some payload) publicKey secretKey
|
||||
|
|
@ -1083,6 +1091,8 @@ let parseArgs (argv: string[]) =
|
|||
ServiceDumpBootstrap = None
|
||||
ServiceDumpFile = None
|
||||
ServiceResize = None
|
||||
ServiceSetUnfreezeOnDemand = None
|
||||
ServiceUnfreezeOnDemandValue = None
|
||||
ServiceSnapshot = None
|
||||
ServiceRestore = None
|
||||
ServiceFrom = None
|
||||
|
|
@ -1219,6 +1229,12 @@ let parseArgs (argv: string[]) =
|
|||
| "--unfreeze" -> i <- i + 1; args.ServiceWake <- Some argv.[i]
|
||||
| "--destroy" -> i <- i + 1; args.ServiceDestroy <- Some argv.[i]
|
||||
| "--resize" -> i <- i + 1; args.ServiceResize <- Some argv.[i]
|
||||
| "--set-unfreeze-on-demand" ->
|
||||
i <- i + 1
|
||||
args.ServiceSetUnfreezeOnDemand <- Some argv.[i]
|
||||
if i + 1 < argv.Length && not (argv.[i + 1].StartsWith("-")) then
|
||||
i <- i + 1
|
||||
args.ServiceUnfreezeOnDemandValue <- Some argv.[i]
|
||||
| "--execute" -> i <- i + 1; args.ServiceExecute <- Some argv.[i]
|
||||
| "--command" -> i <- i + 1; args.ServiceCommand <- Some argv.[i]
|
||||
| "--dump-bootstrap" -> i <- i + 1; args.ServiceDumpBootstrap <- Some argv.[i]
|
||||
|
|
@ -1313,6 +1329,8 @@ let printHelp () =
|
|||
printfn " --unfreeze ID Unfreeze service"
|
||||
printfn " --destroy ID Destroy service"
|
||||
printfn " --resize ID Resize service (requires --vcpu N)"
|
||||
printfn " --set-unfreeze-on-demand ID true|false"
|
||||
printfn " Set unfreeze_on_demand for service"
|
||||
printfn " --execute ID Execute command in service"
|
||||
printfn " --command CMD Command to execute (with --execute)"
|
||||
printfn " --dump-bootstrap ID Dump bootstrap script"
|
||||
|
|
|
|||
|
|
@ -1006,6 +1006,8 @@ class Args {
|
|||
String serviceDumpBootstrap = null
|
||||
String serviceDumpFile = null
|
||||
String serviceResize = null
|
||||
String serviceSetUnfreezeOnDemand = null
|
||||
String serviceUnfreezeOnDemandValue = null
|
||||
String serviceSnapshot = null
|
||||
String serviceRestore = null
|
||||
String serviceFrom = null
|
||||
|
|
@ -1558,6 +1560,14 @@ def cmdService(args) {
|
|||
return
|
||||
}
|
||||
|
||||
if (args.serviceSetUnfreezeOnDemand) {
|
||||
def enabledStr = (args.serviceUnfreezeOnDemandValue ?: 'false').toLowerCase()
|
||||
def enabled = enabledStr in ['true', '1', 'yes', 'on']
|
||||
apiRequestPatch("/services/${args.serviceSetUnfreezeOnDemand}", [unfreeze_on_demand: enabled], publicKey, secretKey)
|
||||
println("${GREEN}Service unfreeze_on_demand set to ${enabled}: ${args.serviceSetUnfreezeOnDemand}${RESET}")
|
||||
return
|
||||
}
|
||||
|
||||
if (args.serviceExecute) {
|
||||
def output = apiRequest("/services/${args.serviceExecute}/execute", 'POST',
|
||||
[command: args.serviceCommand], publicKey, secretKey)
|
||||
|
|
@ -1823,6 +1833,12 @@ def parseArgs(argv) {
|
|||
case '--resize':
|
||||
args.serviceResize = argv[++i]
|
||||
break
|
||||
case '--set-unfreeze-on-demand':
|
||||
args.serviceSetUnfreezeOnDemand = argv[++i]
|
||||
if (i + 1 < argv.size() && !argv[i + 1].startsWith('-')) {
|
||||
args.serviceUnfreezeOnDemandValue = argv[++i]
|
||||
}
|
||||
break
|
||||
case '--execute':
|
||||
args.serviceExecute = argv[++i]
|
||||
break
|
||||
|
|
@ -1900,6 +1916,8 @@ Service options:
|
|||
--unfreeze ID Unfreeze service
|
||||
--destroy ID Destroy service
|
||||
--resize ID Resize service (requires --vcpu N)
|
||||
--set-unfreeze-on-demand ID true|false
|
||||
Set unfreeze_on_demand for service
|
||||
--execute ID Execute command in service
|
||||
--command CMD Command to execute (with --execute)
|
||||
--dump-bootstrap ID Dump bootstrap script
|
||||
|
|
|
|||
|
|
@ -175,6 +175,7 @@ data ServiceAction = ServiceList | ServiceInfo String | ServiceLogs String
|
|||
| ServiceResize String | ServiceExecute String String | ServiceDumpBootstrap String (Maybe String)
|
||||
| ServiceCreate | ServiceSnapshot String | ServiceRestore String
|
||||
| ServiceEnv String (Maybe String) -- action, target
|
||||
| ServiceSetUnfreezeOnDemand String Bool -- service_id, enabled
|
||||
|
||||
data SnapshotOpts = SnapshotOpts
|
||||
{ snapAction :: SnapshotAction
|
||||
|
|
@ -296,6 +297,8 @@ parseService args = return $ parseServiceArgs args defaultServiceOpts
|
|||
parseServiceArgs ("--resize":id:rest) opts = parseServiceArgs rest opts { svcAction = ServiceResize id }
|
||||
parseServiceArgs ("--snapshot":id:rest) opts = parseServiceArgs rest opts { svcAction = ServiceSnapshot id }
|
||||
parseServiceArgs ("--restore":id:rest) opts = parseServiceArgs rest opts { svcAction = ServiceRestore id }
|
||||
parseServiceArgs ("--unfreeze-on-demand":id:"true":rest) opts = parseServiceArgs rest opts { svcAction = ServiceSetUnfreezeOnDemand id True }
|
||||
parseServiceArgs ("--unfreeze-on-demand":id:"false":rest) opts = parseServiceArgs rest opts { svcAction = ServiceSetUnfreezeOnDemand id False }
|
||||
parseServiceArgs ("--execute":id:"--command":cmd:rest) opts = parseServiceArgs rest opts { svcAction = ServiceExecute id cmd }
|
||||
parseServiceArgs ("--dump-bootstrap":id:file:rest) opts = parseServiceArgs rest opts { svcAction = ServiceDumpBootstrap id (Just file) }
|
||||
parseServiceArgs ("--dump-bootstrap":id:rest) opts = parseServiceArgs rest opts { svcAction = ServiceDumpBootstrap id Nothing }
|
||||
|
|
@ -384,6 +387,7 @@ printHelp = do
|
|||
putStrLn " --unfreeze ID Unfreeze service"
|
||||
putStrLn " --destroy ID Destroy service"
|
||||
putStrLn " --resize ID Resize service (requires -v N)"
|
||||
putStrLn " --unfreeze-on-demand ID true|false Enable/disable auto-unfreeze on HTTP request"
|
||||
putStrLn ""
|
||||
putStrLn "Service env commands:"
|
||||
putStrLn " env status ID Check vault status"
|
||||
|
|
@ -592,6 +596,10 @@ serviceCommand opts = do
|
|||
(_, stdout, _) <- curlPost apiKey ("https://api.unsandbox.com/snapshots/" ++ snapshotId ++ "/restore") "{}"
|
||||
putStrLn $ green ++ "Service restored from snapshot" ++ reset
|
||||
putStrLn stdout
|
||||
ServiceSetUnfreezeOnDemand sid enabled -> do
|
||||
let json = "{\"unfreeze_on_demand\":" ++ (if enabled then "true" else "false") ++ "}"
|
||||
(_, stdout, _) <- curlPatch apiKey ("https://api.unsandbox.com/services/" ++ sid) json
|
||||
putStrLn $ green ++ "Service unfreeze_on_demand set to " ++ (if enabled then "true" else "false") ++ ": " ++ sid ++ reset
|
||||
ServiceEnv action maybeTarget -> do
|
||||
case action of
|
||||
"status" -> case maybeTarget of
|
||||
|
|
|
|||
|
|
@ -561,6 +561,17 @@ function cmd_service(args)
|
|||
return
|
||||
end
|
||||
|
||||
if args["unfreeze-on-demand"] !== nothing
|
||||
enabled = args["unfreeze-on-demand-value"]
|
||||
if enabled === nothing
|
||||
println(stderr, "$(RED)Error: --unfreeze-on-demand requires true or false$(RESET)")
|
||||
exit(1)
|
||||
end
|
||||
api_request_patch("/services/$(args["unfreeze-on-demand"])", public_key, secret_key, data=Dict("unfreeze_on_demand" => enabled))
|
||||
println("$(GREEN)Service unfreeze_on_demand set to $(enabled): $(args["unfreeze-on-demand"])$(RESET)")
|
||||
return
|
||||
end
|
||||
|
||||
if args["dump-bootstrap"] !== nothing
|
||||
println(stderr, "Fetching bootstrap script from $(args["dump-bootstrap"])...")
|
||||
payload = Dict("command" => "cat /tmp/bootstrap.sh")
|
||||
|
|
@ -992,6 +1003,11 @@ function main()
|
|||
help = "Destroy service"
|
||||
"--resize"
|
||||
help = "Resize service (requires --vcpu N)"
|
||||
"--unfreeze-on-demand"
|
||||
help = "Service ID to set unfreeze_on_demand for"
|
||||
"--unfreeze-on-demand-value"
|
||||
help = "Enable/disable unfreeze_on_demand (true or false)"
|
||||
arg_type = Bool
|
||||
"--dump-bootstrap"
|
||||
help = "Dump bootstrap script from service"
|
||||
"--dump-file"
|
||||
|
|
|
|||
|
|
@ -103,6 +103,8 @@ data class Args(
|
|||
var serviceDumpBootstrap: String? = null,
|
||||
var serviceDumpFile: String? = null,
|
||||
var serviceResize: String? = null,
|
||||
var serviceUnfreezeOnDemand: String? = null,
|
||||
var serviceUnfreezeOnDemandValue: Boolean? = null,
|
||||
var keyExtend: Boolean = false,
|
||||
var envFile: String? = null,
|
||||
var envAction: String? = null,
|
||||
|
|
@ -363,6 +365,17 @@ fun cmdService(args: Args) {
|
|||
return
|
||||
}
|
||||
|
||||
if (args.serviceUnfreezeOnDemand != null) {
|
||||
if (args.serviceUnfreezeOnDemandValue == null) {
|
||||
System.err.println("${RED}Error: --unfreeze-on-demand requires true or false${RESET}")
|
||||
exitProcess(1)
|
||||
}
|
||||
val payload = mapOf("unfreeze_on_demand" to args.serviceUnfreezeOnDemandValue!!)
|
||||
apiRequestPatch("/services/${args.serviceUnfreezeOnDemand}", payload, publicKey, secretKey)
|
||||
println("${GREEN}Service unfreeze_on_demand set to ${args.serviceUnfreezeOnDemandValue}: ${args.serviceUnfreezeOnDemand}${RESET}")
|
||||
return
|
||||
}
|
||||
|
||||
if (args.serviceExecute != null) {
|
||||
val payload = mutableMapOf<String, Any>("command" to args.serviceCommand!!)
|
||||
val result = apiRequest("/services/${args.serviceExecute}/execute", "POST", payload, publicKey, secretKey)
|
||||
|
|
@ -1145,6 +1158,12 @@ fun parseArgs(args: Array<String>): Args {
|
|||
"--unfreeze" -> result.serviceWake = args[++i]
|
||||
"--destroy" -> result.serviceDestroy = args[++i]
|
||||
"--resize" -> result.serviceResize = args[++i]
|
||||
"--unfreeze-on-demand" -> {
|
||||
result.serviceUnfreezeOnDemand = args[++i]
|
||||
if (i + 1 < args.size && (args[i + 1] == "true" || args[i + 1] == "false")) {
|
||||
result.serviceUnfreezeOnDemandValue = args[++i].toBoolean()
|
||||
}
|
||||
}
|
||||
"--execute" -> result.serviceExecute = args[++i]
|
||||
"--command" -> result.serviceCommand = args[++i]
|
||||
"--dump-bootstrap" -> result.serviceDumpBootstrap = args[++i]
|
||||
|
|
@ -1244,6 +1263,7 @@ Service options:
|
|||
--unfreeze ID Unfreeze service
|
||||
--destroy ID Destroy service
|
||||
--resize ID Resize service (requires --vcpu N)
|
||||
--unfreeze-on-demand ID true|false Enable/disable auto-unfreeze on HTTP request
|
||||
--execute ID Execute command in service
|
||||
--command CMD Command to execute (with --execute)
|
||||
--dump-bootstrap ID Dump bootstrap script
|
||||
|
|
|
|||
|
|
@ -341,6 +341,15 @@
|
|||
(json (format nil "{\"vcpu\":~a}" vcpu)))
|
||||
(curl-patch api-key (format nil "/services/~a" id) json)
|
||||
(format t "~aService resized to ~a vCPU, ~a GB RAM~a~%" *green* vcpu ram *reset*))))
|
||||
((string= action "unfreeze-on-demand")
|
||||
(if (or (null service-type) (string= service-type ""))
|
||||
(progn
|
||||
(format *error-output* "~aError: --unfreeze-on-demand requires true or false~a~%" *red* *reset*)
|
||||
(uiop:quit 1))
|
||||
(let* ((enabled (string= service-type "true"))
|
||||
(json (format nil "{\"unfreeze_on_demand\":~a}" (if enabled "true" "false"))))
|
||||
(curl-patch api-key (format nil "/services/~a" id) json)
|
||||
(format t "~aService unfreeze_on_demand set to ~a: ~a~a~%" *green* (if enabled "true" "false") id *reset*))))
|
||||
((string= action "execute")
|
||||
(when (and id bootstrap)
|
||||
(let* ((json (format nil "{\"command\":\"~a\"}" (escape-json bootstrap)))
|
||||
|
|
@ -700,6 +709,11 @@
|
|||
(fifth args)
|
||||
nil)))
|
||||
(service-cmd "resize" id nil nil nil nil vcpu nil nil nil)))
|
||||
((and (> (length args) 3) (string= (second args) "--unfreeze-on-demand"))
|
||||
;; --unfreeze-on-demand ID true|false: id is third, value is fourth
|
||||
(let ((id (third args))
|
||||
(value (fourth args)))
|
||||
(service-cmd "unfreeze-on-demand" id nil nil nil nil value nil nil nil)))
|
||||
((and (> (length args) 3) (string= (second args) "--execute"))
|
||||
(service-cmd "execute" (third args) nil nil (fourth args) nil nil nil nil nil))
|
||||
((and (> (length args) 3) (string= (second args) "--dump-bootstrap"))
|
||||
|
|
|
|||
|
|
@ -242,6 +242,51 @@ function Un.image_clone(image_id, name, opts)
|
|||
return Un.api_request("POST", "/images/" .. image_id .. "/clone", body, opts)
|
||||
end
|
||||
|
||||
-- Service API functions
|
||||
function Un.service_list(opts)
|
||||
opts = opts or {}
|
||||
return Un.api_request("GET", "/services", nil, opts)
|
||||
end
|
||||
|
||||
function Un.service_get(service_id, opts)
|
||||
opts = opts or {}
|
||||
return Un.api_request("GET", "/services/" .. service_id, nil, opts)
|
||||
end
|
||||
|
||||
function Un.service_set_unfreeze_on_demand(service_id, enabled, opts)
|
||||
opts = opts or {}
|
||||
return Un.api_request_patch("/services/" .. service_id, {unfreeze_on_demand = enabled}, opts)
|
||||
end
|
||||
|
||||
function Un.api_request_patch(endpoint, body, opts)
|
||||
opts = opts or {}
|
||||
local pk, sk = Un.get_credentials(opts)
|
||||
|
||||
local timestamp = tostring(os.time())
|
||||
local url = Un.API_BASE .. endpoint
|
||||
local body_str = body and json.encode(body) or "{}"
|
||||
local signature = Un.sign_request(sk, timestamp, "PATCH", endpoint, body_str)
|
||||
|
||||
local headers = {
|
||||
["Authorization"] = "Bearer " .. pk,
|
||||
["X-Timestamp"] = timestamp,
|
||||
["X-Signature"] = signature,
|
||||
["Content-Type"] = "application/json"
|
||||
}
|
||||
|
||||
local resp_body = {}
|
||||
local resp, status = https.request({
|
||||
url = url,
|
||||
method = "PATCH",
|
||||
headers = headers,
|
||||
source = body_str and ltn12.source.string(body_str),
|
||||
sink = ltn12.sink.table(resp_body)
|
||||
})
|
||||
|
||||
if status ~= 200 then error("API error (" .. status .. ")") end
|
||||
return json.decode(table.concat(resp_body))
|
||||
end
|
||||
|
||||
-- CLI
|
||||
if arg and arg[1] then
|
||||
if arg[1] == "languages" then
|
||||
|
|
@ -257,6 +302,50 @@ if arg and arg[1] then
|
|||
end
|
||||
end
|
||||
os.exit(0)
|
||||
elseif arg[1] == "service" then
|
||||
-- Service command
|
||||
local i = 2
|
||||
local action = nil
|
||||
local service_id = nil
|
||||
local unfreeze_on_demand_value = nil
|
||||
|
||||
while i <= #arg do
|
||||
if arg[i] == "--list" or arg[i] == "-l" then
|
||||
action = "list"
|
||||
elseif arg[i] == "--info" then
|
||||
action = "info"
|
||||
i = i + 1
|
||||
service_id = arg[i]
|
||||
elseif arg[i] == "--unfreeze-on-demand" then
|
||||
action = "unfreeze-on-demand"
|
||||
i = i + 1
|
||||
service_id = arg[i]
|
||||
if i + 1 <= #arg and (arg[i + 1] == "true" or arg[i + 1] == "false") then
|
||||
i = i + 1
|
||||
unfreeze_on_demand_value = arg[i] == "true"
|
||||
end
|
||||
end
|
||||
i = i + 1
|
||||
end
|
||||
|
||||
if action == "list" then
|
||||
local result = Un.service_list()
|
||||
print(json.encode(result))
|
||||
elseif action == "info" then
|
||||
local result = Un.service_get(service_id)
|
||||
print(json.encode(result))
|
||||
elseif action == "unfreeze-on-demand" then
|
||||
if unfreeze_on_demand_value == nil then
|
||||
io.stderr:write("Error: --unfreeze-on-demand requires true or false\n")
|
||||
os.exit(1)
|
||||
end
|
||||
Un.service_set_unfreeze_on_demand(service_id, unfreeze_on_demand_value)
|
||||
print("Service unfreeze_on_demand set to " .. tostring(unfreeze_on_demand_value) .. ": " .. service_id)
|
||||
else
|
||||
io.stderr:write("Error: Use --list, --info ID, or --unfreeze-on-demand ID true|false\n")
|
||||
os.exit(1)
|
||||
end
|
||||
os.exit(0)
|
||||
elseif arg[1] == "image" then
|
||||
-- Image command
|
||||
local i = 2
|
||||
|
|
@ -368,15 +457,22 @@ if arg and arg[1] then
|
|||
elseif arg[1] == "--help" or arg[1] == "-h" then
|
||||
print("Usage: lua un.lua [options] <source_file>")
|
||||
print(" lua un.lua languages [--json]")
|
||||
print(" lua un.lua service [options]")
|
||||
print(" lua un.lua image [options]")
|
||||
print("")
|
||||
print("Commands:")
|
||||
print(" languages [--json] List available programming languages")
|
||||
print(" service [options] Manage services")
|
||||
print(" image [options] Manage images")
|
||||
print("")
|
||||
print("Languages options:")
|
||||
print(" --json Output as JSON array")
|
||||
print("")
|
||||
print("Service options:")
|
||||
print(" --list List all services")
|
||||
print(" --info ID Get service details")
|
||||
print(" --unfreeze-on-demand ID true|false Enable/disable auto-unfreeze on HTTP request")
|
||||
print("")
|
||||
print("Image options:")
|
||||
print(" --list List all images")
|
||||
print(" --info ID Get image details")
|
||||
|
|
|
|||
|
|
@ -379,7 +379,20 @@ proc cmdSession(list: bool, kill, shell, network: string, vcpu: int, tmux, scree
|
|||
let cmd = fmt"""curl -s -X POST '{API_BASE}/sessions' -H 'Content-Type: application/json' {authHeaders} -d '{json}'"""
|
||||
echo execCurl(cmd)
|
||||
|
||||
proc cmdService(name, ports, bootstrap, bootstrapFile, serviceType: string, list: bool, info, logs, tail, sleep, wake, destroy, resize: string, resizeVcpu: int, execute, command, dumpBootstrap, dumpFile, network: string, vcpu: int, inputFiles: seq[string], svcEnvs: seq[string], svcEnvFile, envAction, envTarget: string, publicKey: string, secretKey: string) =
|
||||
proc setServiceUnfreezeOnDemand(serviceId: string, enabled: bool, publicKey: string, secretKey: string): bool =
|
||||
let enabledStr = if enabled: "true" else: "false"
|
||||
let json = fmt"""{{"unfreeze_on_demand":{enabledStr}}}"""
|
||||
let path = fmt"/services/{serviceId}"
|
||||
let authHeaders = buildAuthHeaders("PATCH", path, json, publicKey, secretKey)
|
||||
let cmd = fmt"""curl -s -o /dev/null -w '%{{http_code}}' -X PATCH '{API_BASE}/services/{serviceId}' -H 'Content-Type: application/json' {authHeaders} -d '{json}'"""
|
||||
let output = execProcess(cmd).strip()
|
||||
try:
|
||||
let status = parseInt(output)
|
||||
return status >= 200 and status < 300
|
||||
except:
|
||||
return false
|
||||
|
||||
proc cmdService(name, ports, bootstrap, bootstrapFile, serviceType: string, list: bool, info, logs, tail, sleep, wake, destroy, resize: string, resizeVcpu: int, execute, command, dumpBootstrap, dumpFile, network: string, vcpu: int, unfreezeOnDemand: bool, setUnfreezeOnDemand, setUnfreezeOnDemandEnabled: string, inputFiles: seq[string], svcEnvs: seq[string], svcEnvFile, envAction, envTarget: string, publicKey: string, secretKey: string) =
|
||||
# Handle env subcommand
|
||||
if envAction != "":
|
||||
cmdServiceEnv(envAction, envTarget, svcEnvs, svcEnvFile, publicKey, secretKey)
|
||||
|
|
@ -452,6 +465,16 @@ proc cmdService(name, ports, bootstrap, bootstrapFile, serviceType: string, list
|
|||
echo GREEN & "Service resized to " & $resizeVcpu & " vCPU, " & $ram & " GB RAM" & RESET
|
||||
return
|
||||
|
||||
if setUnfreezeOnDemand != "":
|
||||
let enabled = setUnfreezeOnDemandEnabled == "true" or setUnfreezeOnDemandEnabled == "1"
|
||||
if setServiceUnfreezeOnDemand(setUnfreezeOnDemand, enabled, publicKey, secretKey):
|
||||
let status = if enabled: "enabled" else: "disabled"
|
||||
echo GREEN & "Unfreeze-on-demand " & status & " for service: " & setUnfreezeOnDemand & RESET
|
||||
else:
|
||||
stderr.writeLine(RED & "Error: Failed to update unfreeze-on-demand setting" & RESET)
|
||||
quit(1)
|
||||
return
|
||||
|
||||
if execute != "":
|
||||
let json = fmt"""{"command":"{escapeJson(command)}"}"""
|
||||
let path = fmt"/services/{execute}/execute"
|
||||
|
|
@ -542,6 +565,7 @@ proc cmdService(name, ports, bootstrap, bootstrapFile, serviceType: string, list
|
|||
if serviceType != "": json.add(fmt""","service_type":"{serviceType}"""")
|
||||
if network != "": json.add(fmt""","network":"{network}"""")
|
||||
if vcpu > 0: json.add(fmt""","vcpu":{vcpu}""")
|
||||
if unfreezeOnDemand: json.add(""","unfreeze_on_demand":true""")
|
||||
json.add(buildInputFilesJson(inputFiles))
|
||||
json.add("}")
|
||||
|
||||
|
|
@ -926,6 +950,8 @@ proc main() =
|
|||
var info, logs, tail, sleep, wake, destroy, resize, execute, command, dumpBootstrap, dumpFile, network = ""
|
||||
var vcpu = 0
|
||||
var resizeVcpu = 0
|
||||
var unfreezeOnDemand = false
|
||||
var setUnfreezeOnDemand, setUnfreezeOnDemandEnabled = ""
|
||||
var inputFiles: seq[string] = @[]
|
||||
var svcEnvs: seq[string] = @[]
|
||||
var svcEnvFile = ""
|
||||
|
|
@ -946,7 +972,7 @@ proc main() =
|
|||
of "-k": publicKey = args[i+1]; inc i
|
||||
else: discard
|
||||
inc i
|
||||
cmdService(name, ports, bootstrap, bootstrapFile, serviceType, list, info, logs, tail, sleep, wake, destroy, resize, resizeVcpu, execute, command, dumpBootstrap, dumpFile, network, vcpu, inputFiles, svcEnvs, svcEnvFile, envAction, envTarget, publicKey, secretKey)
|
||||
cmdService(name, ports, bootstrap, bootstrapFile, serviceType, list, info, logs, tail, sleep, wake, destroy, resize, resizeVcpu, execute, command, dumpBootstrap, dumpFile, network, vcpu, unfreezeOnDemand, setUnfreezeOnDemand, setUnfreezeOnDemandEnabled, inputFiles, svcEnvs, svcEnvFile, envAction, envTarget, publicKey, secretKey)
|
||||
return
|
||||
|
||||
while i < args.len:
|
||||
|
|
@ -974,6 +1000,11 @@ proc main() =
|
|||
of "-k": publicKey = args[i+1]; inc i
|
||||
of "-e": svcEnvs.add(args[i+1]); inc i
|
||||
of "--env-file": svcEnvFile = args[i+1]; inc i
|
||||
of "--unfreeze-on-demand": unfreezeOnDemand = true
|
||||
of "--set-unfreeze-on-demand":
|
||||
setUnfreezeOnDemand = args[i+1]
|
||||
setUnfreezeOnDemandEnabled = args[i+2]
|
||||
inc i, 2
|
||||
of "-f":
|
||||
let file = args[i+1]
|
||||
if fileExists(file):
|
||||
|
|
@ -984,7 +1015,7 @@ proc main() =
|
|||
inc i
|
||||
else: discard
|
||||
inc i
|
||||
cmdService(name, ports, bootstrap, bootstrapFile, serviceType, list, info, logs, tail, sleep, wake, destroy, resize, resizeVcpu, execute, command, dumpBootstrap, dumpFile, network, vcpu, inputFiles, svcEnvs, svcEnvFile, envAction, envTarget, publicKey, secretKey)
|
||||
cmdService(name, ports, bootstrap, bootstrapFile, serviceType, list, info, logs, tail, sleep, wake, destroy, resize, resizeVcpu, execute, command, dumpBootstrap, dumpFile, network, vcpu, unfreezeOnDemand, setUnfreezeOnDemand, setUnfreezeOnDemandEnabled, inputFiles, svcEnvs, svcEnvFile, envAction, envTarget, publicKey, secretKey)
|
||||
return
|
||||
|
||||
# Execute mode
|
||||
|
|
|
|||
|
|
@ -1258,6 +1258,15 @@ void cmdSession(NSArray* args) {
|
|||
[YELLOW UTF8String], [RESET UTF8String]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set unfreeze_on_demand flag for a service.
|
||||
*/
|
||||
void setServiceUnfreezeOnDemand(NSString* serviceId, BOOL enabled, NSString* publicKey, NSString* secretKey) {
|
||||
NSString* endpoint = [NSString stringWithFormat:@"/services/%@", serviceId];
|
||||
NSDictionary* payload = @{@"unfreeze_on_demand": @(enabled)};
|
||||
apiRequestCLI(endpoint, @"PATCH", payload, publicKey, secretKey);
|
||||
}
|
||||
|
||||
void cmdService(NSArray* args) {
|
||||
NSString* publicKey, *secretKey;
|
||||
UNGetApiKeysCLI(&publicKey, &secretKey);
|
||||
|
|
@ -1274,6 +1283,9 @@ void cmdService(NSArray* args) {
|
|||
NSString* bootstrapFile = nil;
|
||||
NSString* network = nil;
|
||||
int vcpu = 0;
|
||||
BOOL unfreezeOnDemand = NO;
|
||||
NSString* setUnfreezeOnDemandId = nil;
|
||||
BOOL setUnfreezeOnDemandEnabled = NO;
|
||||
NSMutableArray* inputFiles = [NSMutableArray array];
|
||||
NSMutableArray* envVars = [NSMutableArray array];
|
||||
NSString* envFile = nil;
|
||||
|
|
@ -1351,9 +1363,23 @@ void cmdService(NSArray* args) {
|
|||
network = args[++i];
|
||||
} else if ([arg isEqualToString:@"-v"] && i + 1 < [args count]) {
|
||||
vcpu = [args[++i] intValue];
|
||||
} else if ([arg isEqualToString:@"--unfreeze-on-demand"]) {
|
||||
unfreezeOnDemand = YES;
|
||||
} else if ([arg isEqualToString:@"--set-unfreeze-on-demand"] && i + 2 < [args count]) {
|
||||
setUnfreezeOnDemandId = args[++i];
|
||||
NSString* enabledStr = args[++i];
|
||||
setUnfreezeOnDemandEnabled = [enabledStr isEqualToString:@"true"] || [enabledStr isEqualToString:@"1"];
|
||||
}
|
||||
}
|
||||
|
||||
if (setUnfreezeOnDemandId) {
|
||||
setServiceUnfreezeOnDemand(setUnfreezeOnDemandId, setUnfreezeOnDemandEnabled, publicKey, secretKey);
|
||||
NSString* status = setUnfreezeOnDemandEnabled ? @"enabled" : @"disabled";
|
||||
printf("%sUnfreeze-on-demand %s for service: %s%s\n",
|
||||
[GREEN UTF8String], [status UTF8String], [setUnfreezeOnDemandId UTF8String], [RESET UTF8String]);
|
||||
return;
|
||||
}
|
||||
|
||||
if (listMode) {
|
||||
NSDictionary* result = apiRequestCLI(@"/services", @"GET", nil, publicKey, secretKey);
|
||||
NSArray* services = result[@"services"];
|
||||
|
|
@ -1462,6 +1488,7 @@ void cmdService(NSArray* args) {
|
|||
|
||||
if (network) payload[@"network"] = network;
|
||||
if (vcpu > 0) payload[@"vcpu"] = @(vcpu);
|
||||
if (unfreezeOnDemand) payload[@"unfreeze_on_demand"] = @YES;
|
||||
|
||||
NSDictionary* result = apiRequestCLI(@"/services", @"POST", payload, publicKey, secretKey);
|
||||
printf("%sService created: %s%s\n", [GREEN UTF8String], [result[@"id"] UTF8String], [RESET UTF8String]);
|
||||
|
|
|
|||
|
|
@ -1180,8 +1180,25 @@ let session_command action shell network vcpu input_files =
|
|||
Printf.printf "%s\n" response
|
||||
| _ -> ()
|
||||
|
||||
(* Set unfreeze_on_demand for a service *)
|
||||
let set_service_unfreeze_on_demand service_id enabled =
|
||||
let (public_key, secret_key) = get_api_keys () in
|
||||
let enabled_str = if enabled then "true" else "false" in
|
||||
let json = Printf.sprintf "{\"unfreeze_on_demand\":%s}" enabled_str in
|
||||
let endpoint = Printf.sprintf "/services/%s" service_id in
|
||||
let auth_headers = build_auth_headers public_key secret_key "PATCH" endpoint json in
|
||||
let tmp_file = Printf.sprintf "/tmp/un_ocaml_%d.json" (Random.int 999999) in
|
||||
let oc = open_out tmp_file in
|
||||
output_string oc json;
|
||||
close_out oc;
|
||||
let cmd = Printf.sprintf "curl -s -X PATCH %s%s -H 'Content-Type: application/json'%s -d @%s"
|
||||
api_base endpoint auth_headers tmp_file in
|
||||
let _ = Sys.command cmd in
|
||||
Sys.remove tmp_file;
|
||||
true
|
||||
|
||||
(* Service command *)
|
||||
let service_command action name ports bootstrap bootstrap_file service_type network vcpu input_files envs env_file =
|
||||
let service_command action name ports bootstrap bootstrap_file service_type network vcpu unfreeze_on_demand input_files envs env_file =
|
||||
let api_key = get_api_key () in
|
||||
match action with
|
||||
| "env" ->
|
||||
|
|
@ -1262,6 +1279,16 @@ let service_command action name ports bootstrap bootstrap_file service_type netw
|
|||
| (None, _) ->
|
||||
Printf.fprintf stderr "Error: --resize requires service ID\n";
|
||||
exit 1)
|
||||
| "set_unfreeze_on_demand" ->
|
||||
(match (name, ports) with
|
||||
| (Some sid, Some enabled_str) ->
|
||||
let enabled = enabled_str = "true" || enabled_str = "1" in
|
||||
let _ = set_service_unfreeze_on_demand sid enabled in
|
||||
let status = if enabled then "enabled" else "disabled" in
|
||||
Printf.printf "%sUnfreeze-on-demand %s for service: %s%s\n" green status sid reset
|
||||
| _ ->
|
||||
Printf.fprintf stderr "Error: --set-unfreeze-on-demand requires service ID and enabled (true/false)\n";
|
||||
exit 1)
|
||||
| "execute" ->
|
||||
(match name with
|
||||
| Some sid ->
|
||||
|
|
@ -1316,8 +1343,9 @@ let service_command action name ports bootstrap bootstrap_file service_type netw
|
|||
let service_type_json = match service_type with Some t -> Printf.sprintf ",\"service_type\":\"%s\"" t | None -> "" in
|
||||
let network_json = match network with Some net -> Printf.sprintf ",\"network\":\"%s\"" net | None -> "" in
|
||||
let vcpu_json = match vcpu with Some v -> Printf.sprintf ",\"vcpu\":%d" v | None -> "" in
|
||||
let unfreeze_on_demand_json = if unfreeze_on_demand then ",\"unfreeze_on_demand\":true" else "" in
|
||||
let input_files_json = build_input_files_json input_files in
|
||||
let json = Printf.sprintf "{\"name\":\"%s\"%s%s%s%s%s%s%s}" n ports_json bootstrap_json bootstrap_content_json service_type_json network_json vcpu_json input_files_json in
|
||||
let json = Printf.sprintf "{\"name\":\"%s\"%s%s%s%s%s%s%s%s}" n ports_json bootstrap_json bootstrap_content_json service_type_json network_json vcpu_json unfreeze_on_demand_json input_files_json in
|
||||
let response = curl_post api_key "/services" json in
|
||||
Printf.printf "%sService created%s\n" green reset;
|
||||
Printf.printf "%s\n" response;
|
||||
|
|
@ -1517,36 +1545,38 @@ let () =
|
|||
| _ :: rest -> parse_envs acc rest
|
||||
in
|
||||
let envs = parse_envs [] rest in
|
||||
let rec parse_service action name ports bootstrap bootstrap_file service_type network vcpu env_file = function
|
||||
| [] -> service_command action name ports bootstrap bootstrap_file service_type network vcpu input_files envs env_file
|
||||
let rec parse_service action name ports bootstrap bootstrap_file service_type network vcpu unfreeze_on_demand env_file = function
|
||||
| [] -> service_command action name ports bootstrap bootstrap_file service_type network vcpu unfreeze_on_demand input_files envs env_file
|
||||
| "env" :: env_action :: target :: rest when not (String.length target > 0 && target.[0] = '-') ->
|
||||
parse_service "env_cmd" (Some env_action) (Some target) bootstrap bootstrap_file service_type network vcpu env_file rest
|
||||
parse_service "env_cmd" (Some env_action) (Some target) bootstrap bootstrap_file service_type network vcpu unfreeze_on_demand env_file rest
|
||||
| "env" :: env_action :: rest ->
|
||||
parse_service "env_cmd" (Some env_action) None bootstrap bootstrap_file service_type network vcpu env_file rest
|
||||
| "--list" :: rest -> parse_service "list" name ports bootstrap bootstrap_file service_type network vcpu env_file rest
|
||||
| "--info" :: id :: rest -> parse_service "info" (Some id) ports bootstrap bootstrap_file service_type network vcpu env_file rest
|
||||
| "--logs" :: id :: rest -> parse_service "logs" (Some id) ports bootstrap bootstrap_file service_type network vcpu env_file rest
|
||||
| "--freeze" :: id :: rest -> parse_service "sleep" (Some id) ports bootstrap bootstrap_file service_type network vcpu env_file rest
|
||||
| "--unfreeze" :: id :: rest -> parse_service "wake" (Some id) ports bootstrap bootstrap_file service_type network vcpu env_file rest
|
||||
| "--destroy" :: id :: rest -> parse_service "destroy" (Some id) ports bootstrap bootstrap_file service_type network vcpu env_file rest
|
||||
| "--resize" :: id :: rest -> parse_service "resize" (Some id) ports bootstrap bootstrap_file service_type network vcpu env_file rest
|
||||
| "--vcpu" :: v :: rest -> parse_service action name ports bootstrap bootstrap_file service_type network (Some (int_of_string v)) env_file rest
|
||||
| "--execute" :: id :: "--command" :: cmd :: rest -> parse_service "execute" (Some id) ports (Some cmd) bootstrap_file service_type network vcpu env_file rest
|
||||
| "--dump-bootstrap" :: id :: file :: rest -> parse_service "dump_bootstrap" (Some id) ports bootstrap (Some file) service_type network vcpu env_file rest
|
||||
| "--dump-bootstrap" :: id :: rest -> parse_service "dump_bootstrap" (Some id) ports bootstrap bootstrap_file service_type network vcpu env_file rest
|
||||
| "--name" :: n :: rest -> parse_service "create" (Some n) ports bootstrap bootstrap_file service_type network vcpu env_file rest
|
||||
| "--ports" :: p :: rest -> parse_service action name (Some p) bootstrap bootstrap_file service_type network vcpu env_file rest
|
||||
| "--bootstrap" :: b :: rest -> parse_service action name ports (Some b) bootstrap_file service_type network vcpu env_file rest
|
||||
| "--bootstrap-file" :: f :: rest -> parse_service action name ports bootstrap (Some f) service_type network vcpu env_file rest
|
||||
| "--type" :: t :: rest -> parse_service action name ports bootstrap bootstrap_file (Some t) network vcpu env_file rest
|
||||
| "-n" :: net :: rest -> parse_service action name ports bootstrap bootstrap_file service_type (Some net) vcpu env_file rest
|
||||
| "-v" :: v :: rest -> parse_service action name ports bootstrap bootstrap_file service_type network (Some (int_of_string v)) env_file rest
|
||||
| "--env-file" :: f :: rest -> parse_service action name ports bootstrap bootstrap_file service_type network vcpu (Some f) rest
|
||||
| "-e" :: _ :: rest -> parse_service action name ports bootstrap bootstrap_file service_type network vcpu env_file rest (* skip -e, already parsed *)
|
||||
| "-f" :: _ :: rest -> parse_service action name ports bootstrap bootstrap_file service_type network vcpu env_file rest (* skip -f, already parsed *)
|
||||
| _ :: rest -> parse_service action name ports bootstrap bootstrap_file service_type network vcpu env_file rest
|
||||
parse_service "env_cmd" (Some env_action) None bootstrap bootstrap_file service_type network vcpu unfreeze_on_demand env_file rest
|
||||
| "--list" :: rest -> parse_service "list" name ports bootstrap bootstrap_file service_type network vcpu unfreeze_on_demand env_file rest
|
||||
| "--info" :: id :: rest -> parse_service "info" (Some id) ports bootstrap bootstrap_file service_type network vcpu unfreeze_on_demand env_file rest
|
||||
| "--logs" :: id :: rest -> parse_service "logs" (Some id) ports bootstrap bootstrap_file service_type network vcpu unfreeze_on_demand env_file rest
|
||||
| "--freeze" :: id :: rest -> parse_service "sleep" (Some id) ports bootstrap bootstrap_file service_type network vcpu unfreeze_on_demand env_file rest
|
||||
| "--unfreeze" :: id :: rest -> parse_service "wake" (Some id) ports bootstrap bootstrap_file service_type network vcpu unfreeze_on_demand env_file rest
|
||||
| "--destroy" :: id :: rest -> parse_service "destroy" (Some id) ports bootstrap bootstrap_file service_type network vcpu unfreeze_on_demand env_file rest
|
||||
| "--resize" :: id :: rest -> parse_service "resize" (Some id) ports bootstrap bootstrap_file service_type network vcpu unfreeze_on_demand env_file rest
|
||||
| "--vcpu" :: v :: rest -> parse_service action name ports bootstrap bootstrap_file service_type network (Some (int_of_string v)) unfreeze_on_demand env_file rest
|
||||
| "--execute" :: id :: "--command" :: cmd :: rest -> parse_service "execute" (Some id) ports (Some cmd) bootstrap_file service_type network vcpu unfreeze_on_demand env_file rest
|
||||
| "--dump-bootstrap" :: id :: file :: rest -> parse_service "dump_bootstrap" (Some id) ports bootstrap (Some file) service_type network vcpu unfreeze_on_demand env_file rest
|
||||
| "--dump-bootstrap" :: id :: rest -> parse_service "dump_bootstrap" (Some id) ports bootstrap bootstrap_file service_type network vcpu unfreeze_on_demand env_file rest
|
||||
| "--name" :: n :: rest -> parse_service "create" (Some n) ports bootstrap bootstrap_file service_type network vcpu unfreeze_on_demand env_file rest
|
||||
| "--ports" :: p :: rest -> parse_service action name (Some p) bootstrap bootstrap_file service_type network vcpu unfreeze_on_demand env_file rest
|
||||
| "--bootstrap" :: b :: rest -> parse_service action name ports (Some b) bootstrap_file service_type network vcpu unfreeze_on_demand env_file rest
|
||||
| "--bootstrap-file" :: f :: rest -> parse_service action name ports bootstrap (Some f) service_type network vcpu unfreeze_on_demand env_file rest
|
||||
| "--type" :: t :: rest -> parse_service action name ports bootstrap bootstrap_file (Some t) network vcpu unfreeze_on_demand env_file rest
|
||||
| "-n" :: net :: rest -> parse_service action name ports bootstrap bootstrap_file service_type (Some net) vcpu unfreeze_on_demand env_file rest
|
||||
| "-v" :: v :: rest -> parse_service action name ports bootstrap bootstrap_file service_type network (Some (int_of_string v)) unfreeze_on_demand env_file rest
|
||||
| "--env-file" :: f :: rest -> parse_service action name ports bootstrap bootstrap_file service_type network vcpu unfreeze_on_demand (Some f) rest
|
||||
| "--unfreeze-on-demand" :: rest -> parse_service action name ports bootstrap bootstrap_file service_type network vcpu true env_file rest
|
||||
| "--set-unfreeze-on-demand" :: id :: enabled :: rest -> parse_service "set_unfreeze_on_demand" (Some id) (Some enabled) bootstrap bootstrap_file service_type network vcpu unfreeze_on_demand env_file rest
|
||||
| "-e" :: _ :: rest -> parse_service action name ports bootstrap bootstrap_file service_type network vcpu unfreeze_on_demand env_file rest (* skip -e, already parsed *)
|
||||
| "-f" :: _ :: rest -> parse_service action name ports bootstrap bootstrap_file service_type network vcpu unfreeze_on_demand env_file rest (* skip -f, already parsed *)
|
||||
| _ :: rest -> parse_service action name ports bootstrap bootstrap_file service_type network vcpu unfreeze_on_demand env_file rest
|
||||
in
|
||||
parse_service "create" None None None None None None None None rest
|
||||
parse_service "create" None None None None None None None false None rest
|
||||
| args ->
|
||||
let rec parse_execute file env_vars artifacts out_dir network vcpu = function
|
||||
| [] -> execute_command file env_vars artifacts out_dir network vcpu
|
||||
|
|
|
|||
|
|
@ -733,6 +733,17 @@ sub cmd_service {
|
|||
return;
|
||||
}
|
||||
|
||||
if ($options->{set_unfreeze_on_demand}) {
|
||||
my $enabled = ($options->{set_unfreeze_on_demand_enabled} &&
|
||||
($options->{set_unfreeze_on_demand_enabled} eq 'true' || $options->{set_unfreeze_on_demand_enabled} eq '1'))
|
||||
? JSON::PP::true : JSON::PP::false;
|
||||
my $payload = { unfreeze_on_demand => $enabled };
|
||||
api_request("/services/$options->{set_unfreeze_on_demand}", 'PATCH', $payload, $public_key, $secret_key);
|
||||
my $status = $enabled ? 'enabled' : 'disabled';
|
||||
print "${GREEN}Unfreeze-on-demand $status for service: $options->{set_unfreeze_on_demand}${RESET}\n";
|
||||
return;
|
||||
}
|
||||
|
||||
if ($options->{execute}) {
|
||||
my $payload = { command => $options->{command} };
|
||||
my $result = api_request("/services/$options->{execute}/execute", 'POST', $payload, $public_key, $secret_key);
|
||||
|
|
@ -816,6 +827,7 @@ sub cmd_service {
|
|||
}
|
||||
$payload->{network} = $options->{network} if $options->{network};
|
||||
$payload->{vcpu} = $options->{vcpu} if $options->{vcpu};
|
||||
$payload->{unfreeze_on_demand} = JSON::PP::true if $options->{unfreeze_on_demand};
|
||||
|
||||
my $result = api_request('/services', 'POST', $payload, $public_key, $secret_key);
|
||||
my $service_id = $result->{id};
|
||||
|
|
@ -1170,6 +1182,11 @@ sub main {
|
|||
$options{spawn} = $ARGV[++$i];
|
||||
} elsif ($arg eq '--clone') {
|
||||
$options{clone} = $ARGV[++$i];
|
||||
} elsif ($arg eq '--unfreeze-on-demand') {
|
||||
$options{unfreeze_on_demand} = 1;
|
||||
} elsif ($arg eq '--set-unfreeze-on-demand') {
|
||||
$options{set_unfreeze_on_demand} = $ARGV[++$i];
|
||||
$options{set_unfreeze_on_demand_enabled} = $ARGV[++$i] if defined $ARGV[$i + 1];
|
||||
} elsif ($arg =~ /^-/) {
|
||||
print STDERR "${RED}Unknown option: $arg${RESET}\n";
|
||||
exit 1;
|
||||
|
|
|
|||
|
|
@ -759,6 +759,9 @@ class UnsandboxAsync {
|
|||
if (isset($opts['input_files'])) {
|
||||
$data['input_files'] = $opts['input_files'];
|
||||
}
|
||||
if (isset($opts['unfreeze_on_demand']) && $opts['unfreeze_on_demand']) {
|
||||
$data['unfreeze_on_demand'] = true;
|
||||
}
|
||||
|
||||
return $this->makeRequest('POST', '/services', $publicKey, $secretKey, $data);
|
||||
}
|
||||
|
|
@ -860,6 +863,20 @@ class UnsandboxAsync {
|
|||
return $this->makeRequest('POST', "/services/{$serviceId}/unlock", $publicKey, $secretKey, []);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set unfreeze_on_demand flag for a service.
|
||||
*
|
||||
* @param string $serviceId Service ID
|
||||
* @param bool $enabled Whether to enable unfreeze on demand
|
||||
* @param string|null $publicKey Optional API key
|
||||
* @param string|null $secretKey Optional API secret
|
||||
* @return PromiseInterface Resolves to response array with update confirmation
|
||||
*/
|
||||
public function setUnfreezeOnDemand(string $serviceId, bool $enabled, ?string $publicKey = null, ?string $secretKey = null): PromiseInterface {
|
||||
[$publicKey, $secretKey] = $this->resolveCredentials($publicKey, $secretKey);
|
||||
return $this->makeRequest('PATCH', "/services/{$serviceId}", $publicKey, $secretKey, ['unfreeze_on_demand' => $enabled]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get bootstrap logs for a service.
|
||||
*
|
||||
|
|
@ -1860,6 +1877,14 @@ class UnsandboxAsync {
|
|||
return;
|
||||
}
|
||||
|
||||
if ($serviceOpts['set_unfreeze_on_demand']) {
|
||||
$enabled = in_array($serviceOpts['set_unfreeze_on_demand_enabled'], ['true', '1'], true);
|
||||
$result = $this->setUnfreezeOnDemand($serviceOpts['set_unfreeze_on_demand'], $enabled)->wait();
|
||||
$status = $enabled ? 'enabled' : 'disabled';
|
||||
echo "Unfreeze-on-demand {$status} for service: " . $serviceOpts['set_unfreeze_on_demand'] . "\n";
|
||||
return;
|
||||
}
|
||||
|
||||
// Create new service
|
||||
if (!empty($serviceOpts['name'])) {
|
||||
$createOpts = [];
|
||||
|
|
@ -1875,6 +1900,9 @@ class UnsandboxAsync {
|
|||
if (!empty($serviceOpts['domains'])) {
|
||||
$createOpts['custom_domains'] = explode(',', $serviceOpts['domains']);
|
||||
}
|
||||
if ($serviceOpts['unfreeze_on_demand']) {
|
||||
$createOpts['unfreeze_on_demand'] = true;
|
||||
}
|
||||
|
||||
// Handle bootstrap from file
|
||||
$bootstrap = $serviceOpts['bootstrap'] ?? '';
|
||||
|
|
@ -1940,6 +1968,9 @@ class UnsandboxAsync {
|
|||
'execute_cmd' => null,
|
||||
'snapshot' => null,
|
||||
'snapshot_name' => null,
|
||||
'unfreeze_on_demand' => false,
|
||||
'set_unfreeze_on_demand' => null,
|
||||
'set_unfreeze_on_demand_enabled' => null,
|
||||
];
|
||||
|
||||
$i = 0;
|
||||
|
|
@ -2011,6 +2042,13 @@ class UnsandboxAsync {
|
|||
} elseif ($arg === '--snapshot-name') {
|
||||
$i++;
|
||||
$opts['snapshot_name'] = $args[$i] ?? null;
|
||||
} elseif ($arg === '--unfreeze-on-demand') {
|
||||
$opts['unfreeze_on_demand'] = true;
|
||||
} elseif ($arg === '--set-unfreeze-on-demand') {
|
||||
$i++;
|
||||
$opts['set_unfreeze_on_demand'] = $args[$i] ?? null;
|
||||
$i++;
|
||||
$opts['set_unfreeze_on_demand_enabled'] = $args[$i] ?? null;
|
||||
}
|
||||
|
||||
$i++;
|
||||
|
|
|
|||
|
|
@ -1065,6 +1065,9 @@ class Unsandbox {
|
|||
if (isset($opts['input_files'])) {
|
||||
$data['input_files'] = $opts['input_files'];
|
||||
}
|
||||
if (isset($opts['unfreeze_on_demand']) && $opts['unfreeze_on_demand']) {
|
||||
$data['unfreeze_on_demand'] = true;
|
||||
}
|
||||
|
||||
return $this->makeRequest('POST', '/services', $publicKey, $secretKey, $data);
|
||||
}
|
||||
|
|
@ -1180,6 +1183,22 @@ class Unsandbox {
|
|||
return $this->makeRequest('POST', "/services/{$serviceId}/unlock", $publicKey, $secretKey, []);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set unfreeze_on_demand flag for a service.
|
||||
*
|
||||
* @param string $serviceId Service ID
|
||||
* @param bool $enabled Whether to enable unfreeze on demand
|
||||
* @param string|null $publicKey Optional API key
|
||||
* @param string|null $secretKey Optional API secret
|
||||
* @return array Response array with update confirmation
|
||||
* @throws CredentialsException Missing credentials
|
||||
* @throws ApiException API request failed
|
||||
*/
|
||||
public function setUnfreezeOnDemand(string $serviceId, bool $enabled, ?string $publicKey = null, ?string $secretKey = null): array {
|
||||
[$publicKey, $secretKey] = $this->resolveCredentials($publicKey, $secretKey);
|
||||
return $this->makeRequest('PATCH', "/services/{$serviceId}", $publicKey, $secretKey, ['unfreeze_on_demand' => $enabled]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get bootstrap logs for a service.
|
||||
*
|
||||
|
|
@ -2227,6 +2246,14 @@ class Unsandbox {
|
|||
return;
|
||||
}
|
||||
|
||||
if ($serviceOpts['set_unfreeze_on_demand']) {
|
||||
$enabled = in_array($serviceOpts['set_unfreeze_on_demand_enabled'], ['true', '1'], true);
|
||||
$result = $this->setUnfreezeOnDemand($serviceOpts['set_unfreeze_on_demand'], $enabled);
|
||||
$status = $enabled ? 'enabled' : 'disabled';
|
||||
echo "Unfreeze-on-demand {$status} for service: " . $serviceOpts['set_unfreeze_on_demand'] . "\n";
|
||||
return;
|
||||
}
|
||||
|
||||
// Create new service
|
||||
if (!empty($serviceOpts['name'])) {
|
||||
$createOpts = [];
|
||||
|
|
@ -2242,6 +2269,9 @@ class Unsandbox {
|
|||
if (!empty($serviceOpts['domains'])) {
|
||||
$createOpts['custom_domains'] = explode(',', $serviceOpts['domains']);
|
||||
}
|
||||
if ($serviceOpts['unfreeze_on_demand']) {
|
||||
$createOpts['unfreeze_on_demand'] = true;
|
||||
}
|
||||
|
||||
// Handle bootstrap from file
|
||||
$bootstrap = $serviceOpts['bootstrap'] ?? '';
|
||||
|
|
@ -2307,6 +2337,9 @@ class Unsandbox {
|
|||
'execute_cmd' => null,
|
||||
'snapshot' => null,
|
||||
'snapshot_name' => null,
|
||||
'unfreeze_on_demand' => false,
|
||||
'set_unfreeze_on_demand' => null,
|
||||
'set_unfreeze_on_demand_enabled' => null,
|
||||
];
|
||||
|
||||
$i = 0;
|
||||
|
|
@ -2378,6 +2411,13 @@ class Unsandbox {
|
|||
} elseif ($arg === '--snapshot-name') {
|
||||
$i++;
|
||||
$opts['snapshot_name'] = $args[$i] ?? null;
|
||||
} elseif ($arg === '--unfreeze-on-demand') {
|
||||
$opts['unfreeze_on_demand'] = true;
|
||||
} elseif ($arg === '--set-unfreeze-on-demand') {
|
||||
$i++;
|
||||
$opts['set_unfreeze_on_demand'] = $args[$i] ?? null;
|
||||
$i++;
|
||||
$opts['set_unfreeze_on_demand_enabled'] = $args[$i] ?? null;
|
||||
}
|
||||
|
||||
$i++;
|
||||
|
|
|
|||
|
|
@ -765,6 +765,26 @@ function Invoke-Service {
|
|||
return
|
||||
}
|
||||
|
||||
if ($Args -contains "--set-unfreeze-on-demand") {
|
||||
$idx = [array]::IndexOf($Args, "--set-unfreeze-on-demand")
|
||||
$serviceId = $Args[$idx + 1]
|
||||
$enabled = $Args[$idx + 2]
|
||||
|
||||
if ($enabled -eq "true" -or $enabled -eq "1") {
|
||||
$payload = @{ unfreeze_on_demand = $true } | ConvertTo-Json
|
||||
Invoke-Api -Endpoint "/services/$serviceId" -Method "PATCH" -Body $payload
|
||||
Write-Host "`e[32mUnfreeze-on-demand enabled for service: $serviceId`e[0m"
|
||||
} elseif ($enabled -eq "false" -or $enabled -eq "0") {
|
||||
$payload = @{ unfreeze_on_demand = $false } | ConvertTo-Json
|
||||
Invoke-Api -Endpoint "/services/$serviceId" -Method "PATCH" -Body $payload
|
||||
Write-Host "`e[32mUnfreeze-on-demand disabled for service: $serviceId`e[0m"
|
||||
} else {
|
||||
Write-Error "Error: --set-unfreeze-on-demand requires true/false or 1/0"
|
||||
exit 1
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if ($Args -contains "--dump-bootstrap") {
|
||||
$idx = [array]::IndexOf($Args, "--dump-bootstrap")
|
||||
$serviceId = $Args[$idx + 1]
|
||||
|
|
@ -829,6 +849,10 @@ function Invoke-Service {
|
|||
$payload["service_type"] = $Args[$tIdx + 1]
|
||||
}
|
||||
|
||||
if ($Args -contains "--unfreeze-on-demand") {
|
||||
$payload["unfreeze_on_demand"] = $true
|
||||
}
|
||||
|
||||
# Parse input files
|
||||
$inputFiles = @()
|
||||
for ($i = 0; $i -lt $Args.Count; $i++) {
|
||||
|
|
@ -917,6 +941,7 @@ Service options:
|
|||
--ports PORTS Comma-separated ports
|
||||
--type TYPE Service type (minecraft, mumble, teamspeak, source, tcp, udp)
|
||||
--bootstrap CMD Bootstrap command
|
||||
--unfreeze-on-demand Enable unfreeze-on-demand for new service
|
||||
-f FILE Input file (can be repeated)
|
||||
-e KEY=VALUE Environment variable for vault (can be repeated)
|
||||
--env-file FILE Load vault variables from file
|
||||
|
|
@ -927,6 +952,7 @@ Service options:
|
|||
--unfreeze ID Unfreeze service
|
||||
--destroy ID Destroy service
|
||||
--resize ID Resize service (requires --vcpu or -v)
|
||||
--set-unfreeze-on-demand ID true|false Enable/disable unfreeze-on-demand
|
||||
--dump-bootstrap ID Dump bootstrap script from service
|
||||
--dump-file FILE Save bootstrap to file (with --dump-bootstrap)
|
||||
|
||||
|
|
|
|||
|
|
@ -246,6 +246,19 @@ service_resize(ServiceId, Vcpu) :-
|
|||
[Vcpu, ServiceId, SecretKey, ServiceId, PublicKey, Vcpu, Ram]),
|
||||
shell(Cmd, 0).
|
||||
|
||||
% Service set unfreeze on demand
|
||||
service_set_unfreeze_on_demand(ServiceId, Enabled) :-
|
||||
get_public_key(PublicKey),
|
||||
get_secret_key(SecretKey),
|
||||
( Enabled = true
|
||||
-> EnabledStr = 'true', Msg = 'enabled'
|
||||
; EnabledStr = 'false', Msg = 'disabled'
|
||||
),
|
||||
format(atom(Cmd),
|
||||
'BODY=\'\'{\"unfreeze_on_demand\":~w}\'\'; TIMESTAMP=$(date +%s); MESSAGE="$TIMESTAMP:PATCH:/services/~w:$BODY"; SIGNATURE=$(echo -n "$MESSAGE" | openssl dgst -sha256 -hmac "~w" -hex | sed \'\'s/.*= //\'\'); curl -s -X PATCH https://api.unsandbox.com/services/~w -H "Content-Type: application/json" -H "Authorization: Bearer ~w" -H "X-Timestamp: $TIMESTAMP" -H "X-Signature: $SIGNATURE" -d "$BODY" >/dev/null && echo -e "\\x1b[32mUnfreeze-on-demand ~w for service: ~w\\x1b[0m"',
|
||||
[EnabledStr, ServiceId, SecretKey, ServiceId, PublicKey, Msg, ServiceId]),
|
||||
shell(Cmd, 0).
|
||||
|
||||
% Service env status
|
||||
service_env_status(ServiceId) :-
|
||||
get_public_key(PublicKey),
|
||||
|
|
@ -650,6 +663,14 @@ parse_service_args(['--resize', ServiceId, '-v', VcpuAtom|_], _, _, _, _, _, _,
|
|||
parse_service_args(['--resize', _|_], _, _, _, _, _, _, _, _, _, _) :-
|
||||
write(user_error, '\x1b[31mError: --resize requires --vcpu or -v\x1b[0m\n'),
|
||||
halt(1).
|
||||
parse_service_args(['--set-unfreeze-on-demand', ServiceId, EnabledAtom|_], _, _, _, _, _, _, _, _, _, _) :-
|
||||
( (EnabledAtom = 'true' ; EnabledAtom = '1')
|
||||
-> service_set_unfreeze_on_demand(ServiceId, true)
|
||||
; (EnabledAtom = 'false' ; EnabledAtom = '0')
|
||||
-> service_set_unfreeze_on_demand(ServiceId, false)
|
||||
; write(user_error, '\x1b[31mError: --set-unfreeze-on-demand requires true/false or 1/0\x1b[0m\n'),
|
||||
halt(1)
|
||||
).
|
||||
parse_service_args(['--dump-bootstrap', ServiceId|Rest], _, _, _, _, _, _, _, _, _, _) :-
|
||||
( Rest = ['--dump-file', DumpFile|_]
|
||||
-> service_dump_bootstrap(ServiceId, DumpFile)
|
||||
|
|
|
|||
|
|
@ -1460,6 +1460,19 @@ cmd_service <- function(args) {
|
|||
return()
|
||||
}
|
||||
|
||||
if (!is.null(args$set_unfreeze_on_demand)) {
|
||||
if (is.null(args$set_unfreeze_on_demand_val)) {
|
||||
cat(sprintf("%sError: --set-unfreeze-on-demand requires true/false or 1/0%s\n", RED, RESET), file = stderr())
|
||||
quit(status = 1)
|
||||
}
|
||||
enabled <- args$set_unfreeze_on_demand_val %in% c("true", "1")
|
||||
payload <- list(unfreeze_on_demand = enabled)
|
||||
result <- api_request(paste0("/services/", args$set_unfreeze_on_demand), public_key, secret_key, method = "PATCH", data = payload)
|
||||
status_msg <- if (enabled) "enabled" else "disabled"
|
||||
cat(sprintf("%sUnfreeze-on-demand %s for service: %s%s\n", GREEN, status_msg, args$set_unfreeze_on_demand, RESET))
|
||||
return()
|
||||
}
|
||||
|
||||
if (!is.null(args$snapshot_svc)) {
|
||||
payload <- list()
|
||||
if (!is.null(args$snapshot_name)) {
|
||||
|
|
@ -1550,6 +1563,10 @@ cmd_service <- function(args) {
|
|||
payload$vcpu <- args$vcpu
|
||||
}
|
||||
|
||||
if (!is.null(args$unfreeze_on_demand) && args$unfreeze_on_demand) {
|
||||
payload$unfreeze_on_demand <- TRUE
|
||||
}
|
||||
|
||||
# Add input files
|
||||
if (!is.null(args$files)) {
|
||||
input_files <- list()
|
||||
|
|
@ -1628,6 +1645,9 @@ parse_args <- function() {
|
|||
shell = NULL,
|
||||
dump_bootstrap = NULL,
|
||||
dump_file = NULL,
|
||||
set_unfreeze_on_demand = NULL,
|
||||
set_unfreeze_on_demand_val = NULL,
|
||||
unfreeze_on_demand = FALSE,
|
||||
name = NULL,
|
||||
ports = NULL,
|
||||
domains = NULL,
|
||||
|
|
@ -1764,6 +1784,17 @@ parse_args <- function() {
|
|||
i <- i + 1
|
||||
result$dump_file <- args[i]
|
||||
i <- i + 1
|
||||
} else if (arg == "--set-unfreeze-on-demand") {
|
||||
i <- i + 1
|
||||
result$set_unfreeze_on_demand <- args[i]
|
||||
i <- i + 1
|
||||
if (i <= length(args)) {
|
||||
result$set_unfreeze_on_demand_val <- args[i]
|
||||
i <- i + 1
|
||||
}
|
||||
} else if (arg == "--unfreeze-on-demand") {
|
||||
result$unfreeze_on_demand <- TRUE
|
||||
i <- i + 1
|
||||
} else if (arg == "--name") {
|
||||
i <- i + 1
|
||||
result$name <- args[i]
|
||||
|
|
|
|||
|
|
@ -924,6 +924,8 @@ sub cmd-service(@args) {
|
|||
my $wake-id = '';
|
||||
my $destroy-id = '';
|
||||
my $resize-id = '';
|
||||
my $set-unfreeze-on-demand-id = '';
|
||||
my $set-unfreeze-on-demand-val = False;
|
||||
my $name = '';
|
||||
my $ports = '';
|
||||
my $type = '';
|
||||
|
|
@ -931,6 +933,7 @@ sub cmd-service(@args) {
|
|||
my $bootstrap-file = '';
|
||||
my $network = '';
|
||||
my $vcpu = 0;
|
||||
my $unfreeze-on-demand = False;
|
||||
my @input-files;
|
||||
|
||||
# Parse arguments
|
||||
|
|
@ -964,6 +967,16 @@ sub cmd-service(@args) {
|
|||
$i++;
|
||||
$resize-id = @args[$i];
|
||||
}
|
||||
when '--set-unfreeze-on-demand' {
|
||||
$i++;
|
||||
$set-unfreeze-on-demand-id = @args[$i];
|
||||
$i++;
|
||||
my $val = @args[$i];
|
||||
$set-unfreeze-on-demand-val = ($val eq 'true' || $val eq '1');
|
||||
}
|
||||
when '--unfreeze-on-demand' {
|
||||
$unfreeze-on-demand = True;
|
||||
}
|
||||
when '--name' {
|
||||
$i++;
|
||||
$name = @args[$i];
|
||||
|
|
@ -1059,6 +1072,14 @@ sub cmd-service(@args) {
|
|||
return;
|
||||
}
|
||||
|
||||
if $set-unfreeze-on-demand-id {
|
||||
my %payload = unfreeze_on_demand => $set-unfreeze-on-demand-val;
|
||||
api-request("/services/$set-unfreeze-on-demand-id", 'PATCH', %payload, :$public-key, :$secret-key);
|
||||
my $status = $set-unfreeze-on-demand-val ?? 'enabled' !! 'disabled';
|
||||
say "{$GREEN}Unfreeze-on-demand $status for service: $set-unfreeze-on-demand-id{$RESET}";
|
||||
return;
|
||||
}
|
||||
|
||||
# Create new service
|
||||
if $name {
|
||||
my %payload = name => $name;
|
||||
|
|
@ -1086,6 +1107,7 @@ sub cmd-service(@args) {
|
|||
|
||||
%payload<network> = $network if $network;
|
||||
%payload<vcpu> = $vcpu if $vcpu > 0;
|
||||
%payload<unfreeze_on_demand> = True if $unfreeze-on-demand;
|
||||
|
||||
# Add input files
|
||||
if @input-files {
|
||||
|
|
|
|||
|
|
@ -541,7 +541,8 @@
|
|||
(display response)
|
||||
(newline))))))
|
||||
|
||||
(define (service-cmd action id name ports bootstrap bootstrap-file type input-files env-vars env-file vcpu)
|
||||
(define (service-cmd action id name ports bootstrap bootstrap-file type input-files env-vars env-file vcpu . rest)
|
||||
(define unfreeze-on-demand (and (pair? rest) (car rest)))
|
||||
(let ((api-key (get-api-key)))
|
||||
(cond
|
||||
((equal? action "list")
|
||||
|
|
@ -571,6 +572,17 @@
|
|||
(begin
|
||||
(format (current-error-port) "~aError: --resize requires --vcpu N (1-8)~a\n" red reset)
|
||||
(exit 1))))
|
||||
((equal? action "set-unfreeze-on-demand")
|
||||
(if bootstrap ;; reusing bootstrap as the enabled value
|
||||
(let* ((enabled (or (equal? bootstrap "true") (equal? bootstrap "1")))
|
||||
(enabled-str (if enabled "true" "false"))
|
||||
(msg (if enabled "enabled" "disabled"))
|
||||
(json (format #f "{\"unfreeze_on_demand\":~a}" enabled-str)))
|
||||
(curl-patch api-key (format #f "/services/~a" id) json)
|
||||
(format #t "~aUnfreeze-on-demand ~a for service: ~a~a\n" green msg id reset))
|
||||
(begin
|
||||
(format (current-error-port) "~aError: --set-unfreeze-on-demand requires true/false or 1/0~a\n" red reset)
|
||||
(exit 1))))
|
||||
((equal? action "env-status")
|
||||
(service-env-status api-key id))
|
||||
((equal? action "env-set")
|
||||
|
|
@ -615,8 +627,9 @@
|
|||
(format #f ",\"bootstrap_content\":\"~a\"" (escape-json (read-file bootstrap-file)))
|
||||
""))
|
||||
(type-json (if type (format #f ",\"service_type\":\"~a\"" type) ""))
|
||||
(unfreeze-on-demand-json (if unfreeze-on-demand ",\"unfreeze_on_demand\":true" ""))
|
||||
(input-files-json (build-input-files-json input-files))
|
||||
(json (format #f "{\"name\":\"~a\"~a~a~a~a~a}" name ports-json bootstrap-json bootstrap-content-json type-json input-files-json))
|
||||
(json (format #f "{\"name\":\"~a\"~a~a~a~a~a~a}" name ports-json bootstrap-json bootstrap-content-json type-json unfreeze-on-demand-json input-files-json))
|
||||
(response (curl-post api-key "/services" json))
|
||||
(service-id (json-extract-string response "id")))
|
||||
(format #t "~aService created~a\n" green reset)
|
||||
|
|
@ -852,6 +865,11 @@
|
|||
(loop (cddr args)))
|
||||
(else (loop (cdr args))))))
|
||||
(service-cmd "resize" resize-id #f #f #f #f #f '() '() #f vcpu-val)))
|
||||
((and (> (length args) 3) (equal? (cadr args) "--set-unfreeze-on-demand"))
|
||||
;; Parse --set-unfreeze-on-demand ID true/false
|
||||
(let* ((service-id (caddr args))
|
||||
(enabled-val (list-ref args 3)))
|
||||
(service-cmd "set-unfreeze-on-demand" service-id #f #f enabled-val #f #f '() '() #f #f)))
|
||||
((and (> (length args) 3) (equal? (cadr args) "--execute"))
|
||||
(service-cmd "execute" (caddr args) #f #f (list-ref args 3) #f #f '() '() #f #f))
|
||||
((and (> (length args) 3) (equal? (cadr args) "--dump-bootstrap"))
|
||||
|
|
@ -897,33 +915,37 @@
|
|||
(type #f)
|
||||
(env-vars '())
|
||||
(env-file #f)
|
||||
(unfreeze-on-demand-flag #f)
|
||||
(input-files (parse-input-files rest-args)))
|
||||
;; Parse remaining args
|
||||
(let loop ((args rest-args))
|
||||
(when (and (pair? args) (pair? (cdr args)))
|
||||
(when (pair? args)
|
||||
(cond
|
||||
((equal? (car args) "--ports")
|
||||
((and (pair? (cdr args)) (equal? (car args) "--ports"))
|
||||
(set! ports (cadr args))
|
||||
(loop (cddr args)))
|
||||
((equal? (car args) "--bootstrap")
|
||||
((and (pair? (cdr args)) (equal? (car args) "--bootstrap"))
|
||||
(set! bootstrap (cadr args))
|
||||
(loop (cddr args)))
|
||||
((equal? (car args) "--bootstrap-file")
|
||||
((and (pair? (cdr args)) (equal? (car args) "--bootstrap-file"))
|
||||
(set! bootstrap-file (cadr args))
|
||||
(loop (cddr args)))
|
||||
((equal? (car args) "--type")
|
||||
((and (pair? (cdr args)) (equal? (car args) "--type"))
|
||||
(set! type (cadr args))
|
||||
(loop (cddr args)))
|
||||
((equal? (car args) "-e")
|
||||
((and (pair? (cdr args)) (equal? (car args) "-e"))
|
||||
(set! env-vars (cons (cadr args) env-vars))
|
||||
(loop (cddr args)))
|
||||
((equal? (car args) "--env-file")
|
||||
((and (pair? (cdr args)) (equal? (car args) "--env-file"))
|
||||
(set! env-file (cadr args))
|
||||
(loop (cddr args)))
|
||||
((equal? (car args) "--unfreeze-on-demand")
|
||||
(set! unfreeze-on-demand-flag #t)
|
||||
(loop (cdr args)))
|
||||
((equal? (car args) "-f")
|
||||
(loop (cddr args))) ; skip -f, already parsed
|
||||
(else (loop (cdr args))))))
|
||||
(service-cmd "create" #f name ports bootstrap bootstrap-file type input-files env-vars env-file #f)))
|
||||
(service-cmd "create" #f name ports bootstrap bootstrap-file type input-files env-vars env-file #f unfreeze-on-demand-flag)))
|
||||
(else
|
||||
(display "Error: Invalid service command\n" (current-error-port))
|
||||
(exit 1))))
|
||||
|
|
|
|||
|
|
@ -637,6 +637,7 @@ func createService(
|
|||
customDomains: [String]? = nil,
|
||||
vcpu: Int = 1,
|
||||
serviceType: String? = nil,
|
||||
unfreezeOnDemand: Bool = false,
|
||||
publicKey: String? = nil,
|
||||
secretKey: String? = nil
|
||||
) throws -> [String: Any] {
|
||||
|
|
@ -664,6 +665,9 @@ func createService(
|
|||
if let serviceType = serviceType {
|
||||
data["service_type"] = serviceType
|
||||
}
|
||||
if unfreezeOnDemand {
|
||||
data["unfreeze_on_demand"] = unfreezeOnDemand
|
||||
}
|
||||
|
||||
return try makeRequest(method: "POST", path: "/services", publicKey: pk, secretKey: sk, data: data)
|
||||
}
|
||||
|
|
@ -714,6 +718,12 @@ func unlockService(_ serviceId: String, publicKey: String? = nil, secretKey: Str
|
|||
return try makeRequest(method: "POST", path: "/services/\(serviceId)/unlock", publicKey: pk, secretKey: sk, data: [:])
|
||||
}
|
||||
|
||||
/// Enable or disable automatic unfreezing on incoming requests
|
||||
func setUnfreezeOnDemand(_ serviceId: String, enabled: Bool, publicKey: String? = nil, secretKey: String? = nil) throws -> [String: Any] {
|
||||
let (pk, sk) = try resolveCredentials(publicKey: publicKey, secretKey: secretKey)
|
||||
return try makeRequest(method: "PATCH", path: "/services/\(serviceId)", publicKey: pk, secretKey: sk, data: ["unfreeze_on_demand": enabled])
|
||||
}
|
||||
|
||||
/// Get bootstrap/runtime logs for a service
|
||||
func getServiceLogs(_ serviceId: String, allLogs: Bool = false, publicKey: String? = nil, secretKey: String? = nil) throws -> [String: Any] {
|
||||
let (pk, sk) = try resolveCredentials(publicKey: publicKey, secretKey: secretKey)
|
||||
|
|
|
|||
|
|
@ -979,6 +979,9 @@ proc cmd_service {args} {
|
|||
set env_file ""
|
||||
set env_action ""
|
||||
set env_target ""
|
||||
set unfreeze_on_demand 0
|
||||
set unfreeze_on_demand_id ""
|
||||
set unfreeze_on_demand_enabled ""
|
||||
|
||||
# Parse arguments
|
||||
for {set i 0} {$i < [llength $args]} {incr i} {
|
||||
|
|
@ -1076,6 +1079,15 @@ proc cmd_service {args} {
|
|||
incr i
|
||||
set env_file [lindex $args $i]
|
||||
}
|
||||
--unfreeze-on-demand {
|
||||
set unfreeze_on_demand 1
|
||||
}
|
||||
--set-unfreeze-on-demand {
|
||||
incr i
|
||||
set unfreeze_on_demand_id [lindex $args $i]
|
||||
incr i
|
||||
set unfreeze_on_demand_enabled [lindex $args $i]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1085,6 +1097,19 @@ proc cmd_service {args} {
|
|||
return
|
||||
}
|
||||
|
||||
# Handle set-unfreeze-on-demand
|
||||
if {$unfreeze_on_demand_id ne ""} {
|
||||
set enabled_val [expr {$unfreeze_on_demand_enabled eq "true" || $unfreeze_on_demand_enabled eq "1"}]
|
||||
set payload [list unfreeze_on_demand [::json::write string [expr {$enabled_val ? "true" : "false"}]]]
|
||||
api_request "/services/$unfreeze_on_demand_id" "PATCH" $payload $public_key $secret_key
|
||||
if {$enabled_val} {
|
||||
puts "${::GREEN}Unfreeze-on-demand enabled for service $unfreeze_on_demand_id${::RESET}"
|
||||
} else {
|
||||
puts "${::GREEN}Unfreeze-on-demand disabled for service $unfreeze_on_demand_id${::RESET}"
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if {$list_mode} {
|
||||
set result [api_request "/services" "GET" {} $public_key $secret_key]
|
||||
set services [dict get $result services]
|
||||
|
|
@ -1212,6 +1237,9 @@ proc cmd_service {args} {
|
|||
if {$vcpu > 0} {
|
||||
lappend payload vcpu $vcpu
|
||||
}
|
||||
if {$unfreeze_on_demand} {
|
||||
lappend payload unfreeze_on_demand true
|
||||
}
|
||||
|
||||
# Add input files
|
||||
if {[llength $input_files] > 0} {
|
||||
|
|
|
|||
|
|
@ -411,7 +411,7 @@ fn cmd_session(list bool, kill string, shell string, network string, vcpu int, t
|
|||
println(exec_curl(cmd))
|
||||
}
|
||||
|
||||
fn cmd_service(name string, ports string, service_type string, bootstrap string, bootstrap_file string, list bool, info string, logs string, tail string, sleep string, wake string, destroy string, resize string, execute string, command string, dump_bootstrap string, dump_file string, network string, vcpu int, input_files []string, svc_envs []string, svc_env_file string, api_key string) {
|
||||
fn cmd_service(name string, ports string, service_type string, bootstrap string, bootstrap_file string, list bool, info string, logs string, tail string, sleep string, wake string, destroy string, resize string, execute string, command string, dump_bootstrap string, dump_file string, network string, vcpu int, input_files []string, svc_envs []string, svc_env_file string, unfreeze_on_demand bool, set_unfreeze_on_demand_id string, set_unfreeze_on_demand_enabled string, api_key string) {
|
||||
pub_key := get_public_key()
|
||||
secret_key := get_secret_key()
|
||||
|
||||
|
|
@ -489,6 +489,21 @@ fn cmd_service(name string, ports string, service_type string, bootstrap string,
|
|||
return
|
||||
}
|
||||
|
||||
// Handle set_unfreeze_on_demand
|
||||
if set_unfreeze_on_demand_id != '' {
|
||||
enabled := set_unfreeze_on_demand_enabled == 'true' || set_unfreeze_on_demand_enabled == '1'
|
||||
enabled_str := if enabled { 'true' } else { 'false' }
|
||||
json := '{"unfreeze_on_demand":${enabled_str}}'
|
||||
cmd := "BODY='${json}'; TIMESTAMP=\$(date +%s); MESSAGE=\"\$TIMESTAMP:PATCH:/services/${set_unfreeze_on_demand_id}:\$BODY\"; SIGNATURE=\$(echo -n \"\$MESSAGE\" | openssl dgst -sha256 -hmac '${secret_key}' -hex | sed 's/.*= //'); curl -s -X PATCH '${api_base}/services/${set_unfreeze_on_demand_id}' -H 'Content-Type: application/json' -H 'Authorization: Bearer ${pub_key}' -H \"X-Timestamp: \$TIMESTAMP\" -H \"X-Signature: \$SIGNATURE\" -d \"\$BODY\""
|
||||
exec_curl(cmd)
|
||||
if enabled {
|
||||
println('${green}Unfreeze-on-demand enabled for service ${set_unfreeze_on_demand_id}${reset}')
|
||||
} else {
|
||||
println('${green}Unfreeze-on-demand disabled for service ${set_unfreeze_on_demand_id}${reset}')
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if dump_bootstrap != '' {
|
||||
eprintln('Fetching bootstrap script from ${dump_bootstrap}...')
|
||||
json := '{"command":"cat /tmp/bootstrap.sh"}'
|
||||
|
|
@ -543,6 +558,9 @@ fn cmd_service(name string, ports string, service_type string, bootstrap string,
|
|||
if vcpu > 0 {
|
||||
json += ',"vcpu":${vcpu}'
|
||||
}
|
||||
if unfreeze_on_demand {
|
||||
json += ',"unfreeze_on_demand":true'
|
||||
}
|
||||
json += build_input_files_json(input_files)
|
||||
json += '}'
|
||||
|
||||
|
|
@ -960,6 +978,9 @@ fn main() {
|
|||
mut svc_env_file := ''
|
||||
mut env_action := ''
|
||||
mut env_target := ''
|
||||
mut unfreeze_on_demand := false
|
||||
mut set_unfreeze_on_demand_id := ''
|
||||
mut set_unfreeze_on_demand_enabled := ''
|
||||
|
||||
mut i := 2
|
||||
for i < os.args.len {
|
||||
|
|
@ -1046,6 +1067,15 @@ fn main() {
|
|||
i++
|
||||
svc_env_file = os.args[i]
|
||||
}
|
||||
'--unfreeze-on-demand' { unfreeze_on_demand = true }
|
||||
'--set-unfreeze-on-demand' {
|
||||
i++
|
||||
set_unfreeze_on_demand_id = os.args[i]
|
||||
i++
|
||||
if i < os.args.len {
|
||||
set_unfreeze_on_demand_enabled = os.args[i]
|
||||
}
|
||||
}
|
||||
'-n' {
|
||||
i++
|
||||
network = os.args[i]
|
||||
|
|
@ -1080,7 +1110,7 @@ fn main() {
|
|||
}
|
||||
|
||||
cmd_service(name, ports, service_type, bootstrap, bootstrap_file, list, info, logs, tail, sleep, wake, destroy, resize, execute, command, dump_bootstrap, dump_file, network,
|
||||
vcpu, input_files, svc_envs, svc_env_file, api_key)
|
||||
vcpu, input_files, svc_envs, svc_env_file, unfreeze_on_demand, set_unfreeze_on_demand_id, set_unfreeze_on_demand_enabled, api_key)
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -430,6 +430,9 @@ pub fn main() !u8 {
|
|||
var dump_file: ?[]const u8 = null;
|
||||
var resize: ?[]const u8 = null;
|
||||
var vcpu: i32 = 0;
|
||||
var unfreeze_on_demand = false;
|
||||
var set_unfreeze_on_demand_id: ?[]const u8 = null;
|
||||
var set_unfreeze_on_demand_enabled: ?[]const u8 = null;
|
||||
var input_files = std.ArrayList([]const u8).init(allocator);
|
||||
defer input_files.deinit();
|
||||
var svc_envs = std.ArrayList([]const u8).init(allocator);
|
||||
|
|
@ -489,6 +492,13 @@ pub fn main() !u8 {
|
|||
} else if (mem.eql(u8, args[i], "--env-file") and i + 1 < args.len) {
|
||||
i += 1;
|
||||
svc_env_file = args[i];
|
||||
} else if (mem.eql(u8, args[i], "--unfreeze-on-demand")) {
|
||||
unfreeze_on_demand = true;
|
||||
} else if (mem.eql(u8, args[i], "--set-unfreeze-on-demand") and i + 2 < args.len) {
|
||||
i += 1;
|
||||
set_unfreeze_on_demand_id = args[i];
|
||||
i += 1;
|
||||
set_unfreeze_on_demand_enabled = args[i];
|
||||
} else if (mem.eql(u8, args[i], "-k") and i + 1 < args.len) {
|
||||
i += 1;
|
||||
allocator.free(public_key);
|
||||
|
|
@ -620,6 +630,31 @@ pub fn main() !u8 {
|
|||
// Calculate RAM
|
||||
const ram = vcpu * 2;
|
||||
std.debug.print("\n{s}Service resized to {d} vCPU, {d} GB RAM{s}\n", .{ GREEN, vcpu, ram, RESET });
|
||||
} else if (set_unfreeze_on_demand_id) |svc_id| {
|
||||
// Handle set-unfreeze-on-demand
|
||||
const enabled = if (set_unfreeze_on_demand_enabled) |e|
|
||||
mem.eql(u8, e, "true") or mem.eql(u8, e, "1")
|
||||
else
|
||||
false;
|
||||
const enabled_str = if (enabled) "true" else "false";
|
||||
const json = try std.fmt.allocPrint(allocator, "{{\"unfreeze_on_demand\":{s}}}", .{enabled_str});
|
||||
defer allocator.free(json);
|
||||
|
||||
const path = try std.fmt.allocPrint(allocator, "/services/{s}", .{svc_id});
|
||||
defer allocator.free(path);
|
||||
|
||||
const auth_headers = try buildAuthCmd(allocator, "PATCH", path, json, public_key, secret_key);
|
||||
defer allocator.free(auth_headers);
|
||||
|
||||
const cmd = try std.fmt.allocPrint(allocator, "curl -s -X PATCH '{s}/services/{s}' -H 'Content-Type: application/json' {s} -d '{s}'", .{ API_BASE, svc_id, auth_headers, json });
|
||||
defer allocator.free(cmd);
|
||||
_ = std.c.system(cmd.ptr);
|
||||
|
||||
if (enabled) {
|
||||
std.debug.print("\n{s}Unfreeze-on-demand enabled for service {s}{s}\n", .{ GREEN, svc_id, RESET });
|
||||
} else {
|
||||
std.debug.print("\n{s}Unfreeze-on-demand disabled for service {s}{s}\n", .{ GREEN, svc_id, RESET });
|
||||
}
|
||||
} else if (name) |n| {
|
||||
var json_buf: [65536]u8 = undefined;
|
||||
var json_stream = std.io.fixedBufferStream(&json_buf);
|
||||
|
|
@ -666,6 +701,9 @@ pub fn main() !u8 {
|
|||
}
|
||||
try writer.writeAll("\"");
|
||||
}
|
||||
if (unfreeze_on_demand) {
|
||||
try writer.writeAll(",\"unfreeze_on_demand\":true");
|
||||
}
|
||||
// Add input_files JSON
|
||||
const input_files_json = try buildInputFilesJson(allocator, input_files);
|
||||
defer allocator.free(input_files_json);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue