unoverse 0.1.91 → 0.1.93
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/operator/infra/aws/outputs.tf +3 -0
- package/operator/infra/aws/terraform.tfvars.example +4 -0
- package/operator/infra/aws/variables.tf +11 -0
- package/operator/infra/digitalocean/outputs.tf +3 -0
- package/operator/infra/digitalocean/terraform.tfvars.example +4 -0
- package/operator/infra/digitalocean/variables.tf +11 -0
- package/operator/lib/deploy.sh +64 -11
- package/operator/lib/destroy.sh +10 -7
- package/operator/lib/help.sh +1 -0
- package/operator/operator.sh +2 -2
- package/package.json +1 -1
|
@@ -126,6 +126,9 @@ output "env_production" {
|
|
|
126
126
|
OPENAI_API_KEY=${var.openai_api_key}
|
|
127
127
|
HYPERBROWSER_API_KEY=${var.hyperbrowser_api_key}
|
|
128
128
|
|
|
129
|
+
# Marketplace catalogue (MARKETPLACE.md §5). Empty = local items only.
|
|
130
|
+
UNOVERSE_MARKETPLACE_URL=${var.marketplace_url}
|
|
131
|
+
|
|
129
132
|
# Ingress. With a domain: DOMAIN drives every URL (compose derives
|
|
130
133
|
# https://api.<domain>). Without one (POC): DOMAIN stays empty and the
|
|
131
134
|
# explicit URLs below point at the ALB's DNS name over plain HTTP.
|
|
@@ -53,3 +53,7 @@ roles = [
|
|
|
53
53
|
# that locks every credential users save in the platform. If it's lost, no backup
|
|
54
54
|
# can bring them back. Never commit it; keep a safe copy with your database backups.
|
|
55
55
|
# To change any value: edit this file and re-render. Never hand-edit the output.
|
|
56
|
+
|
|
57
|
+
# Marketplace catalogue to install from (docs/architecture/MARKETPLACE.md).
|
|
58
|
+
# Leave unset for local items only.
|
|
59
|
+
# marketplace_url = "https://marketplace.example.com"
|
|
@@ -91,3 +91,14 @@ variable "hyperbrowser_api_key" {
|
|
|
91
91
|
default = ""
|
|
92
92
|
sensitive = true
|
|
93
93
|
}
|
|
94
|
+
|
|
95
|
+
# The catalogue this universe installs from (MARKETPLACE.md §5). NO DEFAULT, deliberately:
|
|
96
|
+
# a URL is never hardcoded and never a fallback, and absent config means no remote
|
|
97
|
+
# catalogue — the universe serves what it has on disk and in its rows, which is the correct
|
|
98
|
+
# state for development and for air-gapped estates. It reaches the marketplace at install
|
|
99
|
+
# time and at no other time.
|
|
100
|
+
variable "marketplace_url" {
|
|
101
|
+
description = "Base URL of the marketplace catalogue. Empty = local items only."
|
|
102
|
+
type = string
|
|
103
|
+
default = ""
|
|
104
|
+
}
|
|
@@ -118,6 +118,9 @@ output "env_production" {
|
|
|
118
118
|
OPENAI_API_KEY=${var.openai_api_key}
|
|
119
119
|
HYPERBROWSER_API_KEY=${var.hyperbrowser_api_key}
|
|
120
120
|
|
|
121
|
+
# Marketplace catalogue (MARKETPLACE.md §5). Empty = local items only.
|
|
122
|
+
UNOVERSE_MARKETPLACE_URL=${var.marketplace_url}
|
|
123
|
+
|
|
121
124
|
# Ingress. With a domain: DOMAIN drives every URL (compose derives
|
|
122
125
|
# https://api.<domain>). Without one (POC): DOMAIN stays empty and the
|
|
123
126
|
# explicit URLs below point at the load balancer's IP over plain HTTP.
|
|
@@ -50,3 +50,7 @@ openai_api_key = "sk-..." # memory server + OpenAI nodes
|
|
|
50
50
|
# that locks every credential users save in the platform. If it's lost, no backup
|
|
51
51
|
# can bring them back. Never commit it; keep a safe copy with your database backups.
|
|
52
52
|
# To change any value: edit this file and re-render. Never hand-edit the output.
|
|
53
|
+
|
|
54
|
+
# Marketplace catalogue to install from (docs/architecture/MARKETPLACE.md).
|
|
55
|
+
# Leave unset for local items only.
|
|
56
|
+
# marketplace_url = "https://marketplace.example.com"
|
|
@@ -125,3 +125,14 @@ variable "hyperbrowser_api_key" {
|
|
|
125
125
|
default = ""
|
|
126
126
|
sensitive = true
|
|
127
127
|
}
|
|
128
|
+
|
|
129
|
+
# The catalogue this universe installs from (MARKETPLACE.md §5). NO DEFAULT, deliberately:
|
|
130
|
+
# a URL is never hardcoded and never a fallback, and absent config means no remote
|
|
131
|
+
# catalogue — the universe serves what it has on disk and in its rows, which is the correct
|
|
132
|
+
# state for development and for air-gapped estates. It reaches the marketplace at install
|
|
133
|
+
# time and at no other time.
|
|
134
|
+
variable "marketplace_url" {
|
|
135
|
+
description = "Base URL of the marketplace catalogue. Empty = local items only."
|
|
136
|
+
type = string
|
|
137
|
+
default = ""
|
|
138
|
+
}
|
package/operator/lib/deploy.sh
CHANGED
|
@@ -102,14 +102,11 @@ NODE
|
|
|
102
102
|
# password afterwards. This opens a door in the network layer; it does not open the
|
|
103
103
|
# database.
|
|
104
104
|
cmd_db_allow() {
|
|
105
|
-
local cloud
|
|
106
|
-
|
|
107
|
-
[ -
|
|
108
|
-
done
|
|
109
|
-
if [ -z "$cloud" ]; then
|
|
110
|
-
fail "No ground here. There is no database to reach"
|
|
105
|
+
local cloud
|
|
106
|
+
SELF_CMD="unoverse db-allow" cloud=$(_pick_ground "${1:-}") || {
|
|
107
|
+
[ -z "${1:-}" ] && [ ! -d "$ROOT/infra" ] && fail "No ground here. There is no database to reach"
|
|
111
108
|
return 1
|
|
112
|
-
|
|
109
|
+
}
|
|
113
110
|
|
|
114
111
|
local cluster
|
|
115
112
|
cluster=$(grep -E '^existing_pg_cluster_name[[:space:]]*=' "$ROOT/infra/$cloud/terraform.tfvars" 2>/dev/null | sed -E 's/.*"([^"]+)".*/\1/')
|
|
@@ -188,6 +185,51 @@ NODE
|
|
|
188
185
|
# `unoverse destroy` ran with no credential at all and every API call came back 401 —
|
|
189
186
|
# the same class of bug as the Postgres question living in one branch of two. Anything
|
|
190
187
|
# that talks to a ground calls this first.
|
|
188
|
+
# WHICH GROUND THIS COMMAND MEANS.
|
|
189
|
+
# _pick_ground [name] → echoes the ground, or fails with a reason
|
|
190
|
+
#
|
|
191
|
+
# Every command used `for g in digitalocean aws; do ... break; done`: first match wins, and
|
|
192
|
+
# digitalocean is first in the list. With both grounds configured there was no way to reach
|
|
193
|
+
# the AWS one — and `unoverse destroy` would have torn down DigitalOcean while the operator
|
|
194
|
+
# meant AWS, silently, because the word "aws" had nowhere to go.
|
|
195
|
+
#
|
|
196
|
+
# So a ground can be named. With one configured, naming it is optional and the answer is
|
|
197
|
+
# obvious. With two, the name is REQUIRED rather than guessed: a wrong guess here destroys
|
|
198
|
+
# the wrong cloud.
|
|
199
|
+
_pick_ground() {
|
|
200
|
+
local want="${1:-}" g found=""
|
|
201
|
+
case "$want" in
|
|
202
|
+
do|digitalocean) want="digitalocean" ;;
|
|
203
|
+
aws|amazon) want="aws" ;;
|
|
204
|
+
"") want="" ;;
|
|
205
|
+
*) fail "Unknown ground '$want'. Use ${BOLD}digitalocean${NC} or ${BOLD}aws${NC}" >&2; return 1 ;;
|
|
206
|
+
esac
|
|
207
|
+
|
|
208
|
+
local configured=()
|
|
209
|
+
for g in digitalocean aws; do
|
|
210
|
+
[ -f "$ROOT/infra/$g/terraform.tfvars" ] && configured+=("$g")
|
|
211
|
+
done
|
|
212
|
+
|
|
213
|
+
if [ -n "$want" ]; then
|
|
214
|
+
for g in "${configured[@]}"; do
|
|
215
|
+
[ "$g" = "$want" ] && { printf '%s' "$want"; return 0; }
|
|
216
|
+
done
|
|
217
|
+
fail "No $want ground here. Run ${BOLD}unoverse deploy $want${NC} to create one" >&2
|
|
218
|
+
return 1
|
|
219
|
+
fi
|
|
220
|
+
|
|
221
|
+
case "${#configured[@]}" in
|
|
222
|
+
0) return 1 ;; # caller offers to create one
|
|
223
|
+
1) printf '%s' "${configured[0]}"; return 0 ;;
|
|
224
|
+
*)
|
|
225
|
+
# Two grounds and no name. Refuse rather than pick: this decides which cloud a
|
|
226
|
+
# destroy lands on.
|
|
227
|
+
fail "Two grounds are configured. Say which: ${BOLD}${SELF_CMD:-unoverse deploy} digitalocean${NC} or ${BOLD}${SELF_CMD:-unoverse deploy} aws${NC}" >&2
|
|
228
|
+
return 1
|
|
229
|
+
;;
|
|
230
|
+
esac
|
|
231
|
+
}
|
|
232
|
+
|
|
191
233
|
_ground_credentials() {
|
|
192
234
|
[ -n "${DIGITALOCEAN_TOKEN:-}" ] && return 0
|
|
193
235
|
local _docfg
|
|
@@ -472,6 +514,13 @@ _ground_apply() {
|
|
|
472
514
|
}
|
|
473
515
|
|
|
474
516
|
cmd_deploy() {
|
|
517
|
+
# A LEADING GROUND NAME IS NOT A SUBCOMMAND. `unoverse deploy aws` names the cloud;
|
|
518
|
+
# `unoverse deploy init` names the step; `unoverse deploy aws init` does both. Take the
|
|
519
|
+
# ground off the front when it is there, and leave everything else exactly as it was.
|
|
520
|
+
local GROUND_ARG=""
|
|
521
|
+
case "${1:-}" in
|
|
522
|
+
do|digitalocean|aws|amazon) GROUND_ARG="$1"; shift ;;
|
|
523
|
+
esac
|
|
475
524
|
|
|
476
525
|
# .env.production IS NOT A FILE IN THE UNIVERSE. It is `terraform output -raw
|
|
477
526
|
# env_production`: derived, complete, and regenerated in full on every deploy. Writing it
|
|
@@ -492,10 +541,14 @@ cmd_deploy() {
|
|
|
492
541
|
# ── ONE FLOW ────────────────────────────────────────────────────────────────
|
|
493
542
|
# Which ground, is it configured, plan it, apply it, ship it. In that order, every
|
|
494
543
|
# time, whether this is the first deploy or the fiftieth.
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
544
|
+
# A named ground wins; one configured ground is implied; two without a name is refused
|
|
545
|
+
# (see _pick_ground). Nothing configured at all falls through to creating one below,
|
|
546
|
+
# which is the first-run path and the only case where an empty answer is not a mistake.
|
|
547
|
+
local cloud="" rc have=0
|
|
548
|
+
[ -f "$ROOT/infra/digitalocean/terraform.tfvars" ] || [ -f "$ROOT/infra/aws/terraform.tfvars" ] && have=1
|
|
549
|
+
if [ "$have" = "1" ]; then
|
|
550
|
+
cloud=$(SELF_CMD="unoverse deploy" _pick_ground "${GROUND_ARG:-}") || exit 1
|
|
551
|
+
fi
|
|
499
552
|
|
|
500
553
|
if [ -z "$cloud" ]; then
|
|
501
554
|
echo ""
|
package/operator/lib/destroy.sh
CHANGED
|
@@ -19,14 +19,17 @@
|
|
|
19
19
|
# cloud resources this ground owns.
|
|
20
20
|
|
|
21
21
|
cmd_destroy() {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
22
|
+
# NAME THE GROUND. This took the first configured one, and digitalocean is first in the
|
|
23
|
+
# list — so an operator with both grounds who typed `unoverse destroy` meaning AWS would
|
|
24
|
+
# have torn down DigitalOcean instead, with the confirmation prompt happily naming the
|
|
25
|
+
# universe they thought they were destroying. _pick_ground refuses to guess when there is
|
|
26
|
+
# more than one.
|
|
27
|
+
local cloud
|
|
28
|
+
cloud=$(SELF_CMD="unoverse destroy" _pick_ground "${1:-}") || {
|
|
29
|
+
[ -f "$ROOT/infra/digitalocean/terraform.tfvars" ] || [ -f "$ROOT/infra/aws/terraform.tfvars" ] \
|
|
30
|
+
|| fail "No ground here. There is nothing deployed to take down"
|
|
28
31
|
return 1
|
|
29
|
-
|
|
32
|
+
}
|
|
30
33
|
|
|
31
34
|
local dir="$ROOT/infra/$cloud"
|
|
32
35
|
if [ ! -d "$dir/.terraform" ]; then
|
package/operator/lib/help.sh
CHANGED
|
@@ -24,6 +24,7 @@ cmd_help() {
|
|
|
24
24
|
echo -e " ${GREEN}logs${NC} What is it doing ${DIM}(unoverse logs <service> for one)${NC}"
|
|
25
25
|
echo -e " ${GREEN}deploy${NC} Ship it to a server ${DIM}(first run asks which cloud)${NC}"
|
|
26
26
|
echo -e " ${GREEN}destroy${NC} Take the deployment down ${DIM}(shows what goes, and what stays)${NC}"
|
|
27
|
+
echo -e " ${DIM}With two grounds, name one: deploy aws · destroy digitalocean${NC}"
|
|
27
28
|
echo -e " ${GREEN}db-allow${NC} Let this machine reach the database ${DIM}(run it when you change network)${NC}"
|
|
28
29
|
echo ""
|
|
29
30
|
# Owner-only lane. Printed ONLY when publish.sh is present, so a starter kit never
|
package/operator/operator.sh
CHANGED
|
@@ -65,8 +65,8 @@ case "${1:-}" in
|
|
|
65
65
|
check) cmd_check && cmd_db_verify && cmd_doctor ;;
|
|
66
66
|
dev) cmd_dev ;;
|
|
67
67
|
ground) shift; cmd_ground "$@" ;;
|
|
68
|
-
destroy) cmd_destroy ;;
|
|
69
|
-
db-allow) cmd_db_allow ;;
|
|
68
|
+
destroy) cmd_destroy "${2:-}" ;;
|
|
69
|
+
db-allow) cmd_db_allow "${2:-}" ;;
|
|
70
70
|
refresh-images)
|
|
71
71
|
# internal: `unoverse update` runs this after updating the CLI. Pull newer images
|
|
72
72
|
# if the registry has them, and recreate only what is already running — an update
|
package/package.json
CHANGED