unoverse 0.1.100 → 0.1.101
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/main.tf +13 -1
- package/operator/infra/aws/variables.tf +10 -0
- package/operator/lib/deploy.sh +12 -14
- package/operator/lib/ground.sh +22 -2
- package/package.json +1 -1
|
@@ -242,10 +242,22 @@ data "aws_ami" "ubuntu" {
|
|
|
242
242
|
}
|
|
243
243
|
}
|
|
244
244
|
|
|
245
|
+
# The key pair, from the operator's own public key. AWS accepts an imported key, so nothing
|
|
246
|
+
# has to pre-exist in the account and no private key is ever downloaded or stored.
|
|
247
|
+
resource "aws_key_pair" "operator" {
|
|
248
|
+
count = var.operator_public_key != "" ? 1 : 0
|
|
249
|
+
key_name = "${var.name}-operator"
|
|
250
|
+
public_key = var.operator_public_key
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
locals {
|
|
254
|
+
key_name = var.operator_public_key != "" ? aws_key_pair.operator[0].key_name : var.ssh_key_name
|
|
255
|
+
}
|
|
256
|
+
|
|
245
257
|
resource "aws_instance" "app" {
|
|
246
258
|
ami = data.aws_ami.ubuntu.id
|
|
247
259
|
instance_type = local.s.instance
|
|
248
|
-
key_name =
|
|
260
|
+
key_name = local.key_name
|
|
249
261
|
vpc_security_group_ids = [aws_security_group.app.id]
|
|
250
262
|
|
|
251
263
|
root_block_device {
|
|
@@ -102,3 +102,13 @@ variable "marketplace_url" {
|
|
|
102
102
|
type = string
|
|
103
103
|
default = ""
|
|
104
104
|
}
|
|
105
|
+
|
|
106
|
+
# YOUR public key, uploaded as this universe's EC2 key pair. Deploying means ssh-ing from
|
|
107
|
+
# the machine that runs `unoverse deploy`, so the key that must work is the one that machine
|
|
108
|
+
# holds — not whichever pair happens to exist in the account. Empty falls back to
|
|
109
|
+
# ssh_key_name, for an operator with no local key.
|
|
110
|
+
variable "operator_public_key" {
|
|
111
|
+
description = "An ssh public key (the contents of ~/.ssh/id_ed25519.pub). Empty = use ssh_key_name instead."
|
|
112
|
+
type = string
|
|
113
|
+
default = ""
|
|
114
|
+
}
|
package/operator/lib/deploy.sh
CHANGED
|
@@ -540,9 +540,8 @@ _ground_apply() {
|
|
|
540
540
|
}
|
|
541
541
|
|
|
542
542
|
cmd_deploy() {
|
|
543
|
-
# A LEADING GROUND NAME IS NOT A SUBCOMMAND. `unoverse deploy aws` names the cloud
|
|
544
|
-
#
|
|
545
|
-
# ground off the front when it is there, and leave everything else exactly as it was.
|
|
543
|
+
# A LEADING GROUND NAME IS NOT A SUBCOMMAND. `unoverse deploy aws` names the cloud. Take
|
|
544
|
+
# it off the front when it is there, and leave everything else exactly as it was.
|
|
546
545
|
local GROUND_ARG=""
|
|
547
546
|
case "${1:-}" in
|
|
548
547
|
do|digitalocean|aws|amazon) GROUND_ARG="$1"; shift ;;
|
|
@@ -700,9 +699,8 @@ EOF
|
|
|
700
699
|
# A FIRST DEPLOY TO A NEW SERVER IS A PROVISION, NOT AN IMAGE PULL. Bare `deploy` meant
|
|
701
700
|
# only "pull the latest images and restart", which on a freshly built droplet fails on
|
|
702
701
|
# "Destination directory /opt/gravity does not exist" — /opt/gravity being the directory
|
|
703
|
-
# install.yml creates.
|
|
704
|
-
#
|
|
705
|
-
# journey, so it asks the server what it is and picks the right playbook itself.
|
|
702
|
+
# install.yml creates. Deploy owns the whole journey, so it asks the server what it is and
|
|
703
|
+
# picks the right playbook itself rather than expecting anyone to know a second command.
|
|
706
704
|
# THE MARKER IS "SETUP FINISHED", NOT "A DIRECTORY EXISTS". Testing for /opt/gravity
|
|
707
705
|
# looked right and was not: install.yml creates that directory as its seventh task, so a
|
|
708
706
|
# first-time setup that then FAILED at the database step still left it behind. The next
|
|
@@ -714,7 +712,7 @@ EOF
|
|
|
714
712
|
"$deploy_user@$deploy_host" 'test -f /opt/gravity/.setup-complete' >/dev/null 2>&1; then
|
|
715
713
|
echo ""
|
|
716
714
|
info "This server's setup has not finished. Running it ${DIM}(install, database, verify)${NC}"
|
|
717
|
-
subcommand="
|
|
715
|
+
subcommand="first-time"
|
|
718
716
|
fi
|
|
719
717
|
fi
|
|
720
718
|
|
|
@@ -732,10 +730,10 @@ EOF
|
|
|
732
730
|
-e "universe_root=$ROOT" \
|
|
733
731
|
-e "env_file=$env_prod"
|
|
734
732
|
;;
|
|
735
|
-
|
|
736
|
-
#
|
|
737
|
-
#
|
|
738
|
-
#
|
|
733
|
+
first-time)
|
|
734
|
+
# INTERNAL, never typed. Deploy reaches this by finding no .setup-complete stamp on
|
|
735
|
+
# the server: install → database → verify, end to end. Hardening stays a deliberate
|
|
736
|
+
# follow-up (POCs get verified first; harden when you decide to keep the box).
|
|
739
737
|
info "First-time setup: install → database → verify"
|
|
740
738
|
echo ""
|
|
741
739
|
info "[1/3] Provisioning (Docker, services, mounts)..."
|
|
@@ -743,7 +741,7 @@ EOF
|
|
|
743
741
|
-i "$tmp_inventory" \
|
|
744
742
|
"$ansible_dir/playbooks/install.yml" \
|
|
745
743
|
-e "universe_root=$ROOT" \
|
|
746
|
-
-e "env_file=$env_prod" || { rm -f "$tmp_inventory"; fail "install failed
|
|
744
|
+
-e "env_file=$env_prod" || { rm -f "$tmp_inventory"; fail "install failed. Fix the error above, then: unoverse deploy $cloud"; exit 1; }
|
|
747
745
|
echo ""
|
|
748
746
|
info "[2/3] Database setup..."
|
|
749
747
|
ansible-playbook \
|
|
@@ -751,14 +749,14 @@ EOF
|
|
|
751
749
|
"$ansible_dir/playbooks/db-setup.yml" \
|
|
752
750
|
-e "universe_root=$ROOT" \
|
|
753
751
|
-e "pg_admin_url=$pg_admin_url" \
|
|
754
|
-
-e "env_file=$env_prod" || { rm -f "$tmp_inventory"; fail "
|
|
752
|
+
-e "env_file=$env_prod" || { rm -f "$tmp_inventory"; fail "database setup failed. Fix the error above, then: unoverse deploy $cloud"; exit 1; }
|
|
755
753
|
echo ""
|
|
756
754
|
info "[3/3] Verifying..."
|
|
757
755
|
ansible-playbook \
|
|
758
756
|
-i "$tmp_inventory" \
|
|
759
757
|
"$ansible_dir/playbooks/test-connectivity.yml" \
|
|
760
758
|
-e "universe_root=$ROOT" \
|
|
761
|
-
-e "env_file=$env_prod" || { rm -f "$tmp_inventory"; fail "verification failed
|
|
759
|
+
-e "env_file=$env_prod" || { rm -f "$tmp_inventory"; fail "verification failed. Look at the output above, then: unoverse deploy $cloud"; exit 1; }
|
|
762
760
|
# Only now. Every step passed, so the next deploy can safely be an image push.
|
|
763
761
|
ssh -o BatchMode=yes -o StrictHostKeyChecking=accept-new -o ConnectTimeout=15 \
|
|
764
762
|
"$deploy_user@$deploy_host" 'touch /opt/gravity/.setup-complete' >/dev/null 2>&1
|
package/operator/lib/ground.sh
CHANGED
|
@@ -239,9 +239,28 @@ _ground_aws() {
|
|
|
239
239
|
region=$(aws configure get region 2>/dev/null)
|
|
240
240
|
[ -n "$region" ] && ok "region: $region" || { region="us-east-1"; info "no default region configured. Using us-east-1"; }
|
|
241
241
|
|
|
242
|
+
# A KEY PAIR YOU CANNOT USE IS NOT A KEY PAIR. This took the FIRST key pair in the region,
|
|
243
|
+
# which on a real account is whatever was created years ago in the console — its private
|
|
244
|
+
# half is not on this laptop, so terraform applied happily and Ansible then died on
|
|
245
|
+
# "Permission denied (publickey)" after eleven minutes of RDS provisioning.
|
|
246
|
+
#
|
|
247
|
+
# The operator's own key is the one that works, because deploying IS ssh-ing from here.
|
|
248
|
+
# Upload it under the universe's name and use that: AWS lets terraform import a public
|
|
249
|
+
# key, so nothing has to pre-exist and nothing has to be downloaded. Fall back to the
|
|
250
|
+
# account's existing pairs only when this machine has no key at all.
|
|
251
|
+
local pubkey=""
|
|
252
|
+
for pubkey in "$HOME/.ssh/id_ed25519.pub" "$HOME/.ssh/id_rsa.pub" ""; do
|
|
253
|
+
[ -n "$pubkey" ] && [ -f "$pubkey" ] && break
|
|
254
|
+
done
|
|
255
|
+
|
|
242
256
|
keys=$(aws ec2 describe-key-pairs --query 'KeyPairs[].KeyName' --output text 2>/dev/null | tr '\t' '\n')
|
|
243
257
|
first_key=$(echo "$keys" | head -1)
|
|
244
|
-
if [ -n "$
|
|
258
|
+
if [ -n "$pubkey" ]; then
|
|
259
|
+
first_key="" # terraform creates the pair from operator_public_key
|
|
260
|
+
ok "SSH key: your own ${DIM}($(basename "$pubkey") — uploaded as ${GROUND_NAME:-this universe}-operator)${NC}"
|
|
261
|
+
elif [ -n "$first_key" ]; then
|
|
262
|
+
warn "no SSH key on this machine — using the account's ${BOLD}$first_key${NC}"
|
|
263
|
+
warn "the deploy will fail unless you hold its private half"
|
|
245
264
|
ok "EC2 key pair: $first_key"
|
|
246
265
|
else
|
|
247
266
|
warn "no EC2 key pairs in $region. Create one first (aws ec2 create-key-pair)"
|
|
@@ -268,7 +287,8 @@ _ground_aws() {
|
|
|
268
287
|
region = "$region"
|
|
269
288
|
name = "$GROUND_NAME"
|
|
270
289
|
admin_cidr = "${ip:-FILL_ME}${ip:+/32}" # YOUR IP — the only SSH source
|
|
271
|
-
ssh_key_name = "${first_key
|
|
290
|
+
ssh_key_name = "${first_key}" # empty = terraform uploads operator_public_key below
|
|
291
|
+
operator_public_key = "$( [ -n "$pubkey" ] && cat "$pubkey" )" # your key: the deploy ssh-es from this machine
|
|
272
292
|
admin_email = "FILL_ME" # initial admin (Cognito user, all roles; invite emailed)
|
|
273
293
|
size = "small" # small (POC) | medium | large
|
|
274
294
|
# Domain is OPTIONAL — empty brings the universe up on the ALB's DNS name over
|
package/package.json
CHANGED