direxio-deployer 0.1.0
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/AGENTS.md +92 -0
- package/LICENSE +21 -0
- package/README.md +221 -0
- package/README_zh.md +218 -0
- package/SKILL.md +722 -0
- package/agents/README.md +25 -0
- package/agents/openai.yaml +12 -0
- package/bin/direxio-deployer.mjs +375 -0
- package/package.json +28 -0
- package/references/agent-targets.md +128 -0
- package/references/architecture.md +44 -0
- package/references/bug-history.md +78 -0
- package/references/deployment-lessons.md +218 -0
- package/references/deployment-optimization-audit.md +317 -0
- package/references/deployment-workflow.md +341 -0
- package/references/iam-policy.json +52 -0
- package/references/runtime-wiring.md +209 -0
- package/references/state-machine.md +46 -0
- package/references/token-refresh.md +81 -0
- package/references/tooling.md +106 -0
- package/references/troubleshooting.md +26 -0
- package/references/user-journey.md +75 -0
- package/references/verification-recovery.md +84 -0
- package/references/voip-turn-runbook.md +154 -0
- package/references/windows-deployment-notes.md +119 -0
- package/scripts/aws-credentials.sh +195 -0
- package/scripts/cloud-init/Caddyfile +48 -0
- package/scripts/cloud-init/docker-compose.yml +125 -0
- package/scripts/cloud-init/init-tokens.sh +238 -0
- package/scripts/cloud-init/user-data.yaml +40 -0
- package/scripts/destroy.ps1 +77 -0
- package/scripts/destroy.sh +589 -0
- package/scripts/lib/aws.sh +73 -0
- package/scripts/lib/domain.sh +175 -0
- package/scripts/lib/operation_report.sh +240 -0
- package/scripts/lib/ops.sh +230 -0
- package/scripts/lib/paths.sh +35 -0
- package/scripts/lib/state.sh +137 -0
- package/scripts/mcp-tools-list.mjs +95 -0
- package/scripts/orchestrate.ps1 +112 -0
- package/scripts/orchestrate.sh +1126 -0
- package/scripts/phases/s0_prereq_aws.sh +39 -0
- package/scripts/phases/s1_preflight.sh +72 -0
- package/scripts/phases/s2_domain.sh +103 -0
- package/scripts/phases/s3_provision.sh +421 -0
- package/scripts/phases/s4_bootstrap_stack.sh +38 -0
- package/scripts/phases/s5_init_tokens.sh +118 -0
- package/scripts/phases/s6_wire_local.sh +1435 -0
- package/scripts/phases/s7_verify_e2e.sh +136 -0
- package/scripts/pricing-estimate.sh +256 -0
- package/scripts/render/render-userdata.sh +86 -0
- package/scripts/reset-app-data.sh +40 -0
- package/scripts/update.sh +30 -0
- package/tests/aws_credentials_test.sh +139 -0
- package/tests/connect_daemon_runtime_check_test.sh +120 -0
- package/tests/default_paths_test.sh +58 -0
- package/tests/destroy_local_bridge_test.sh +154 -0
- package/tests/destroy_root_identity_test.sh +91 -0
- package/tests/destroy_route53_zone_test.sh +80 -0
- package/tests/domain_authoritative_dns_test.sh +49 -0
- package/tests/mcp_doctor_runtime_check_test.sh +86 -0
- package/tests/mcp_smoke_runtime_check_test.sh +121 -0
- package/tests/mcp_tools_runtime_check_test.sh +123 -0
- package/tests/npm_skill_distribution_test.sh +95 -0
- package/tests/operation_report_test.sh +258 -0
- package/tests/orchestrate_status_recovery_test.sh +91 -0
- package/tests/phase_timeout_test.sh +88 -0
- package/tests/pricing_estimate_test.sh +159 -0
- package/tests/render_userdata_remote_nodes_test.sh +40 -0
- package/tests/root_volume_tracking_test.sh +41 -0
- package/tests/route53_overwrite_guard_test.sh +86 -0
- package/tests/route53_zone_auto_create_test.sh +66 -0
- package/tests/runtime_summary_check_test.sh +203 -0
- package/tests/s6_wire_local_test.sh +405 -0
- package/tests/skill_structure_test.sh +298 -0
- package/tests/update_reset_ops_test.sh +230 -0
- package/tests/user_confirmation_gates_test.sh +152 -0
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
ROOT=$(cd "$(dirname "$0")/.." && pwd)
|
|
5
|
+
tmp=$(mktemp -d)
|
|
6
|
+
trap 'rm -rf "$tmp"' EXIT
|
|
7
|
+
|
|
8
|
+
export HOME="$tmp/home"
|
|
9
|
+
mkdir -p "$HOME"
|
|
10
|
+
|
|
11
|
+
fakebin="$tmp/bin"
|
|
12
|
+
mkdir -p "$fakebin"
|
|
13
|
+
|
|
14
|
+
cat > "$fakebin/aws" <<'EOF'
|
|
15
|
+
#!/usr/bin/env bash
|
|
16
|
+
set -euo pipefail
|
|
17
|
+
printf 'aws' >> "$CALLS"
|
|
18
|
+
printf ' %q' "$@" >> "$CALLS"
|
|
19
|
+
printf '\n' >> "$CALLS"
|
|
20
|
+
|
|
21
|
+
case "${1:-} ${2:-}" in
|
|
22
|
+
"configure get")
|
|
23
|
+
exit 1
|
|
24
|
+
;;
|
|
25
|
+
"sts get-caller-identity")
|
|
26
|
+
profile=${AWS_PROFILE:-}
|
|
27
|
+
key=${AWS_ACCESS_KEY_ID:-}
|
|
28
|
+
if [ "$profile" = "root-profile" ] || [ "$key" = "AKIAROOTTEST" ]; then
|
|
29
|
+
arn="arn:aws:iam::123456789012:root"
|
|
30
|
+
account="123456789012"
|
|
31
|
+
else
|
|
32
|
+
arn="arn:aws:iam::123456789012:user/DirexioDeployer-20260628"
|
|
33
|
+
account="123456789012"
|
|
34
|
+
fi
|
|
35
|
+
case "$*" in
|
|
36
|
+
*"--query Arn"*) printf '%s\n' "$arn" ;;
|
|
37
|
+
*"--query Account"*) printf '%s\n' "$account" ;;
|
|
38
|
+
*) printf '{"Account":"%s","Arn":"%s"}\n' "$account" "$arn" ;;
|
|
39
|
+
esac
|
|
40
|
+
;;
|
|
41
|
+
*)
|
|
42
|
+
echo "unexpected aws call: $*" >&2
|
|
43
|
+
exit 2
|
|
44
|
+
;;
|
|
45
|
+
esac
|
|
46
|
+
EOF
|
|
47
|
+
chmod 700 "$fakebin/aws"
|
|
48
|
+
|
|
49
|
+
CALLS="$tmp/aws.calls"
|
|
50
|
+
export CALLS
|
|
51
|
+
export PATH="$fakebin:$PATH"
|
|
52
|
+
export AWS_SHARED_CREDENTIALS_FILE="$tmp/aws/credentials"
|
|
53
|
+
export AWS_CONFIG_FILE="$tmp/aws/config"
|
|
54
|
+
|
|
55
|
+
file_mode() {
|
|
56
|
+
if stat -c '%a' "$1" >/dev/null 2>&1; then
|
|
57
|
+
stat -c '%a' "$1"
|
|
58
|
+
else
|
|
59
|
+
stat -f '%Lp' "$1"
|
|
60
|
+
fi
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
cat > "$tmp/direxio.csv" <<'CSV'
|
|
64
|
+
User name,Access key ID,Secret access key
|
|
65
|
+
DirexioDeployer-20260628,AKIADIREXIOTEST,SECRET_DIREXIO_VALUE
|
|
66
|
+
CSV
|
|
67
|
+
|
|
68
|
+
out=$(bash "$ROOT/scripts/aws-credentials.sh" import-csv "$tmp/direxio.csv" direxio-deployer ap-southeast-1)
|
|
69
|
+
|
|
70
|
+
[[ "$out" == *"profile=direxio-deployer"* ]]
|
|
71
|
+
[[ "$out" == *"arn:aws:iam::<account>:user/DirexioDeployer-20260628"* ]]
|
|
72
|
+
if [[ "$out" == *"AKIADIREXIOTEST"* || "$out" == *"SECRET_DIREXIO_VALUE"* ]]; then
|
|
73
|
+
echo "aws-credentials output leaked credential values" >&2
|
|
74
|
+
printf '%s\n' "$out" >&2
|
|
75
|
+
exit 1
|
|
76
|
+
fi
|
|
77
|
+
|
|
78
|
+
grep -q '^\[direxio-deployer\]$' "$AWS_SHARED_CREDENTIALS_FILE"
|
|
79
|
+
grep -q '^aws_access_key_id = AKIADIREXIOTEST$' "$AWS_SHARED_CREDENTIALS_FILE"
|
|
80
|
+
grep -q '^aws_secret_access_key = SECRET_DIREXIO_VALUE$' "$AWS_SHARED_CREDENTIALS_FILE"
|
|
81
|
+
grep -q '^\[profile direxio-deployer\]$' "$AWS_CONFIG_FILE"
|
|
82
|
+
grep -q '^region = ap-southeast-1$' "$AWS_CONFIG_FILE"
|
|
83
|
+
|
|
84
|
+
credential_perm=$(file_mode "$AWS_SHARED_CREDENTIALS_FILE")
|
|
85
|
+
config_perm=$(file_mode "$AWS_CONFIG_FILE")
|
|
86
|
+
case "$(uname -s)" in
|
|
87
|
+
MINGW*|MSYS*|CYGWIN*)
|
|
88
|
+
[[ "$credential_perm" == "600" || "$credential_perm" == "644" ]]
|
|
89
|
+
[[ "$config_perm" == "600" || "$config_perm" == "644" ]]
|
|
90
|
+
;;
|
|
91
|
+
*)
|
|
92
|
+
[ "$credential_perm" = "600" ]
|
|
93
|
+
[ "$config_perm" = "600" ]
|
|
94
|
+
;;
|
|
95
|
+
esac
|
|
96
|
+
|
|
97
|
+
verify_out=$(AWS_PROFILE=direxio-deployer bash "$ROOT/scripts/aws-credentials.sh" verify direxio-deployer)
|
|
98
|
+
[[ "$verify_out" == *"profile=direxio-deployer"* ]]
|
|
99
|
+
[[ "$verify_out" == *"root=false"* ]]
|
|
100
|
+
|
|
101
|
+
cat > "$tmp/root.csv" <<'CSV'
|
|
102
|
+
Access key ID,Secret access key
|
|
103
|
+
AKIAROOTTEST,SECRET_ROOT_VALUE
|
|
104
|
+
CSV
|
|
105
|
+
|
|
106
|
+
root_out=$(bash "$ROOT/scripts/aws-credentials.sh" import-csv "$tmp/root.csv" root-profile us-east-1)
|
|
107
|
+
[[ "$root_out" == *"profile=root-profile"* ]]
|
|
108
|
+
[[ "$root_out" == *"root=true"* ]]
|
|
109
|
+
if [[ "$root_out" == *"AKIAROOTTEST"* || "$root_out" == *"SECRET_ROOT_VALUE"* ]]; then
|
|
110
|
+
echo "aws-credentials root output leaked credential values" >&2
|
|
111
|
+
printf '%s\n' "$root_out" >&2
|
|
112
|
+
exit 1
|
|
113
|
+
fi
|
|
114
|
+
grep -q '^\[root-profile\]$' "$AWS_SHARED_CREDENTIALS_FILE"
|
|
115
|
+
grep -q '^aws_access_key_id = AKIAROOTTEST$' "$AWS_SHARED_CREDENTIALS_FILE"
|
|
116
|
+
grep -q '^aws_secret_access_key = SECRET_ROOT_VALUE$' "$AWS_SHARED_CREDENTIALS_FILE"
|
|
117
|
+
|
|
118
|
+
root_verify_out=$(AWS_PROFILE=root-profile bash "$ROOT/scripts/aws-credentials.sh" verify root-profile)
|
|
119
|
+
[[ "$root_verify_out" == *"profile=root-profile"* ]]
|
|
120
|
+
[[ "$root_verify_out" == *"root=true"* ]]
|
|
121
|
+
|
|
122
|
+
set +e
|
|
123
|
+
s0_output=$(
|
|
124
|
+
P2P_WORKDIR="$tmp/state-root" AWS_PROFILE=root-profile bash -c '
|
|
125
|
+
set -uo pipefail
|
|
126
|
+
cd "$1"
|
|
127
|
+
source scripts/lib/state.sh
|
|
128
|
+
state_init >/dev/null 2>&1
|
|
129
|
+
source scripts/lib/aws.sh
|
|
130
|
+
source scripts/phases/s0_prereq_aws.sh
|
|
131
|
+
run_phase
|
|
132
|
+
' _ "$ROOT" 2>&1
|
|
133
|
+
)
|
|
134
|
+
s0_rc=$?
|
|
135
|
+
set -e
|
|
136
|
+
[ "$s0_rc" -eq 0 ]
|
|
137
|
+
[[ "$s0_output" == *"AWS credentials are valid"* ]]
|
|
138
|
+
|
|
139
|
+
echo "aws credentials ok"
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
ROOT=$(cd "$(dirname "$0")/.." && pwd)
|
|
5
|
+
tmp=$(mktemp -d)
|
|
6
|
+
trap 'rm -rf "$tmp"' EXIT
|
|
7
|
+
|
|
8
|
+
export HOME="$tmp/home"
|
|
9
|
+
mkdir -p "$HOME"
|
|
10
|
+
|
|
11
|
+
fakebin="$tmp/bin"
|
|
12
|
+
mkdir -p "$fakebin"
|
|
13
|
+
cat > "$fakebin/direxio-connect" <<'EOF'
|
|
14
|
+
#!/usr/bin/env bash
|
|
15
|
+
set -euo pipefail
|
|
16
|
+
|
|
17
|
+
if [ "${1:-}" = "daemon" ] && [ "${2:-}" = "logs" ]; then
|
|
18
|
+
[ "${3:-}" = "--service-name" ]
|
|
19
|
+
[ "${4:-}" = "connect-check.example.test" ]
|
|
20
|
+
printf '%s\n' "${CONNECT_LOG_OUTPUT:-}"
|
|
21
|
+
exit 0
|
|
22
|
+
fi
|
|
23
|
+
|
|
24
|
+
[ "${1:-}" = "daemon" ]
|
|
25
|
+
[ "${2:-}" = "status" ]
|
|
26
|
+
[ "${3:-}" = "--service-name" ]
|
|
27
|
+
[ "${4:-}" = "connect-check.example.test" ]
|
|
28
|
+
|
|
29
|
+
cat <<STATUS
|
|
30
|
+
cc-connect daemon status
|
|
31
|
+
|
|
32
|
+
Status: ${CONNECT_STATUS:-Running}
|
|
33
|
+
Platform: test
|
|
34
|
+
WorkDir: ${CONNECT_WORK_DIR:-}
|
|
35
|
+
STATUS
|
|
36
|
+
EOF
|
|
37
|
+
chmod 700 "$fakebin/direxio-connect"
|
|
38
|
+
|
|
39
|
+
service_dir="$HOME/.direxio/nodes/connect-check.example.test"
|
|
40
|
+
mkdir -p "$service_dir/cc-connect"
|
|
41
|
+
config="$service_dir/cc-connect/config.toml"
|
|
42
|
+
: > "$config"
|
|
43
|
+
state="$service_dir/state.json"
|
|
44
|
+
jq -n \
|
|
45
|
+
--arg service_dir "$service_dir" \
|
|
46
|
+
--arg config "$config" \
|
|
47
|
+
'{
|
|
48
|
+
run_id: "connect-daemon-test",
|
|
49
|
+
region: "ap-northeast-1",
|
|
50
|
+
domain_mode: "user",
|
|
51
|
+
domain: "connect-check.example.test",
|
|
52
|
+
agent_service_id: "connect-check.example.test",
|
|
53
|
+
agent_service_dir: $service_dir,
|
|
54
|
+
cc_connect_config: $config,
|
|
55
|
+
cc_connect_binary: "direxio-connect",
|
|
56
|
+
phase: "S7_VERIFY_E2E",
|
|
57
|
+
phases: {
|
|
58
|
+
S0_PREREQ_AWS: {status: "done"},
|
|
59
|
+
S1_PREFLIGHT: {status: "done"},
|
|
60
|
+
S2_DOMAIN: {status: "done"},
|
|
61
|
+
S3_PROVISION: {status: "done"},
|
|
62
|
+
S4_BOOTSTRAP_STACK: {status: "done"},
|
|
63
|
+
S5_INIT_TOKENS: {status: "done"},
|
|
64
|
+
S6_WIRE_LOCAL: {status: "done"},
|
|
65
|
+
S7_VERIFY_E2E: {status: "done"}
|
|
66
|
+
},
|
|
67
|
+
resources: {}
|
|
68
|
+
}' > "$state"
|
|
69
|
+
|
|
70
|
+
verify_output=$(P2P_WORKDIR="$service_dir" PATH="$fakebin:$PATH" CONNECT_WORK_DIR="$service_dir/cc-connect" bash "$ROOT/scripts/orchestrate.sh" verify connect_daemon)
|
|
71
|
+
printf '%s\n' "$verify_output" | grep -q 'verified runtime check: connect_daemon'
|
|
72
|
+
|
|
73
|
+
expected_work_dir="$service_dir/cc-connect"
|
|
74
|
+
if command -v cygpath >/dev/null 2>&1; then
|
|
75
|
+
expected_work_dir=$(cygpath -m "$expected_work_dir")
|
|
76
|
+
fi
|
|
77
|
+
|
|
78
|
+
jq -e '
|
|
79
|
+
.runtime_checks.connect_daemon.status == "passed"
|
|
80
|
+
and .runtime_checks.connect_daemon.service_name == "connect-check.example.test"
|
|
81
|
+
and .runtime_checks.connect_daemon.daemon_status == "Running"
|
|
82
|
+
and .runtime_checks.connect_daemon.work_dir == "'"$expected_work_dir"'"
|
|
83
|
+
and (.user_confirmations.agent_mcp_runtime | not)
|
|
84
|
+
' "$state" >/dev/null
|
|
85
|
+
|
|
86
|
+
set +e
|
|
87
|
+
P2P_WORKDIR="$service_dir" PATH="$fakebin:$PATH" CONNECT_WORK_DIR="$service_dir/cc-connect" CONNECT_LOG_OUTPUT='ACP error (ACP_SESSION_INIT_FAILED): ACP metadata is missing for agent:main:acp:a18569b4-1f24-4f8a-aec6-f6a54530d50e. Recreate this ACP session with /acp spawn and rebind the thread.' bash "$ROOT/scripts/orchestrate.sh" verify connect_daemon > "$tmp/acp-error.out" 2>&1
|
|
88
|
+
acp_rc=$?
|
|
89
|
+
set -e
|
|
90
|
+
[ "$acp_rc" -ne 0 ] || {
|
|
91
|
+
echo "connect daemon check must fail when daemon logs show ACP session init failure" >&2
|
|
92
|
+
exit 1
|
|
93
|
+
}
|
|
94
|
+
jq -e '
|
|
95
|
+
.runtime_checks.connect_daemon.status == "failed"
|
|
96
|
+
and (.runtime_checks.connect_daemon.evidence | contains("ACP session initialization failure"))
|
|
97
|
+
and (.runtime_checks.connect_daemon.agent_error | contains("ACP_SESSION_INIT_FAILED"))
|
|
98
|
+
' "$state" >/dev/null
|
|
99
|
+
|
|
100
|
+
report_output=$(P2P_WORKDIR="$service_dir" bash "$ROOT/scripts/orchestrate.sh" report new_deploy)
|
|
101
|
+
report_path=$(printf '%s\n' "$report_output" | sed -nE 's/^operation report: //p' | tail -n 1)
|
|
102
|
+
jq -e '
|
|
103
|
+
.runtime_checks.connect_daemon.status == "failed"
|
|
104
|
+
and .gates.user_confirmation.agent_mcp_runtime == "pending_runtime_confirmation"
|
|
105
|
+
' "$report_path" >/dev/null
|
|
106
|
+
|
|
107
|
+
set +e
|
|
108
|
+
P2P_WORKDIR="$service_dir" PATH="$fakebin:$PATH" CONNECT_WORK_DIR="$HOME/.direxio/nodes/other.example.test/cc-connect" bash "$ROOT/scripts/orchestrate.sh" verify connect_daemon > "$tmp/wrong.out" 2>&1
|
|
109
|
+
wrong_rc=$?
|
|
110
|
+
set -e
|
|
111
|
+
[ "$wrong_rc" -ne 0 ] || {
|
|
112
|
+
echo "connect daemon check must fail when daemon WorkDir belongs to another service" >&2
|
|
113
|
+
exit 1
|
|
114
|
+
}
|
|
115
|
+
jq -e '
|
|
116
|
+
.runtime_checks.connect_daemon.status == "failed"
|
|
117
|
+
and (.runtime_checks.connect_daemon.evidence | contains("different service"))
|
|
118
|
+
' "$state" >/dev/null
|
|
119
|
+
|
|
120
|
+
echo "connect daemon runtime check ok"
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
ROOT=$(cd "$(dirname "$0")/.." && pwd)
|
|
5
|
+
tmp=$(mktemp -d)
|
|
6
|
+
trap 'rm -rf "$tmp"' EXIT
|
|
7
|
+
|
|
8
|
+
export HOME="$tmp/home"
|
|
9
|
+
mkdir -p "$HOME"
|
|
10
|
+
unset P2P_WORKDIR
|
|
11
|
+
unset DIREXIO_WORKDIR
|
|
12
|
+
export DOMAIN="IM.Example.test"
|
|
13
|
+
|
|
14
|
+
# shellcheck disable=SC1090
|
|
15
|
+
source "$ROOT/scripts/lib/state.sh"
|
|
16
|
+
|
|
17
|
+
[ "$P2P_WORKDIR" = "$HOME/.direxio/nodes/im.example.test" ]
|
|
18
|
+
[ "$STATE_JSON" = "$HOME/.direxio/nodes/im.example.test/state.json" ]
|
|
19
|
+
|
|
20
|
+
(
|
|
21
|
+
unset P2P_WORKDIR
|
|
22
|
+
export DIREXIO_WORKDIR="$HOME/.direxio/custom-workdir"
|
|
23
|
+
# shellcheck disable=SC1090
|
|
24
|
+
source "$ROOT/scripts/lib/state.sh"
|
|
25
|
+
[ "$P2P_WORKDIR" = "$HOME/.direxio/custom-workdir" ]
|
|
26
|
+
[ "$STATE_JSON" = "$HOME/.direxio/custom-workdir/state.json" ]
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
rm -rf "$HOME/.direxio"
|
|
30
|
+
(
|
|
31
|
+
unset DOMAIN P2P_WORKDIR DIREXIO_WORKDIR
|
|
32
|
+
HOME="$HOME" bash "$ROOT/scripts/orchestrate.sh" status >/dev/null 2>&1
|
|
33
|
+
)
|
|
34
|
+
[ ! -e "$HOME/.direxio/deploy" ]
|
|
35
|
+
[ ! -e "$HOME/.direxio/nodes/state.json" ]
|
|
36
|
+
|
|
37
|
+
mkdir -p "$HOME/.direxio/nodes/solo.example.test"
|
|
38
|
+
jq -n '{domain:"solo.example.test", phase:"S3_PROVISION", resources:{instance_id:"i-solo"}}' > "$HOME/.direxio/nodes/solo.example.test/state.json"
|
|
39
|
+
(
|
|
40
|
+
unset DOMAIN P2P_WORKDIR DIREXIO_WORKDIR
|
|
41
|
+
# shellcheck disable=SC1090
|
|
42
|
+
source "$ROOT/scripts/lib/state.sh"
|
|
43
|
+
[ "$P2P_WORKDIR" = "$HOME/.direxio/nodes" ]
|
|
44
|
+
[ "$STATE_JSON" = "$HOME/.direxio/nodes/state.json" ]
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
mkdir -p "$HOME/.direxio/nodes/second.example.test"
|
|
48
|
+
jq -n '{domain:"second.example.test", phase:"S6_WIRE_LOCAL", resources:{instance_id:"i-second"}}' > "$HOME/.direxio/nodes/second.example.test/state.json"
|
|
49
|
+
status_output=$(
|
|
50
|
+
unset DOMAIN P2P_WORKDIR DIREXIO_WORKDIR
|
|
51
|
+
HOME="$HOME" bash "$ROOT/scripts/orchestrate.sh" status
|
|
52
|
+
)
|
|
53
|
+
[[ "$status_output" == *"solo.example.test"* ]]
|
|
54
|
+
[[ "$status_output" == *"second.example.test"* ]]
|
|
55
|
+
[[ "$status_output" == *"i-solo"* ]]
|
|
56
|
+
[[ "$status_output" == *"i-second"* ]]
|
|
57
|
+
|
|
58
|
+
echo "default paths ok"
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
ROOT=$(cd "$(dirname "$0")/.." && pwd)
|
|
5
|
+
tmp=$(mktemp -d)
|
|
6
|
+
trap 'rm -rf "$tmp"' EXIT
|
|
7
|
+
|
|
8
|
+
export HOME="$tmp/home"
|
|
9
|
+
mkdir -p "$HOME"
|
|
10
|
+
|
|
11
|
+
fakebin="$tmp/bin"
|
|
12
|
+
mkdir -p "$fakebin"
|
|
13
|
+
|
|
14
|
+
cat > "$fakebin/aws" <<'EOF'
|
|
15
|
+
#!/usr/bin/env bash
|
|
16
|
+
set -euo pipefail
|
|
17
|
+
printf 'aws' >> "$CALLS"
|
|
18
|
+
printf ' %q' "$@" >> "$CALLS"
|
|
19
|
+
printf '\n' >> "$CALLS"
|
|
20
|
+
|
|
21
|
+
case "${1:-} ${2:-}" in
|
|
22
|
+
"sts get-caller-identity")
|
|
23
|
+
case "$*" in
|
|
24
|
+
*"--query Arn"*) printf 'arn:aws:iam::123456789012:user/DirexioDeployer-Test\n' ;;
|
|
25
|
+
*"--query Account"*) printf '123456789012\n' ;;
|
|
26
|
+
*) printf '{"Account":"123456789012","Arn":"arn:aws:iam::123456789012:user/DirexioDeployer-Test"}\n' ;;
|
|
27
|
+
esac
|
|
28
|
+
;;
|
|
29
|
+
"ec2 terminate-instances") exit 0 ;;
|
|
30
|
+
"ec2 wait") exit 0 ;;
|
|
31
|
+
"ec2 release-address") exit 0 ;;
|
|
32
|
+
"ec2 delete-security-group") exit 0 ;;
|
|
33
|
+
"ec2 delete-key-pair") exit 0 ;;
|
|
34
|
+
*) exit 0 ;;
|
|
35
|
+
esac
|
|
36
|
+
EOF
|
|
37
|
+
chmod 700 "$fakebin/aws"
|
|
38
|
+
|
|
39
|
+
cat > "$fakebin/direxio-connect" <<'EOF'
|
|
40
|
+
#!/usr/bin/env bash
|
|
41
|
+
set -euo pipefail
|
|
42
|
+
printf 'direxio-connect' >> "$CALLS"
|
|
43
|
+
printf ' %q' "$@" >> "$CALLS"
|
|
44
|
+
printf '\n' >> "$CALLS"
|
|
45
|
+
if [ "${1:-}" = "daemon" ] && [ "${2:-}" = "status" ]; then
|
|
46
|
+
[ "${3:-}" = "--service-name" ]
|
|
47
|
+
[ -n "${4:-}" ]
|
|
48
|
+
cat <<STATUS
|
|
49
|
+
cc-connect daemon status
|
|
50
|
+
|
|
51
|
+
Status: Running
|
|
52
|
+
Platform: test
|
|
53
|
+
WorkDir: ${STATUS_WORK_DIR:-}
|
|
54
|
+
STATUS
|
|
55
|
+
fi
|
|
56
|
+
EOF
|
|
57
|
+
chmod 700 "$fakebin/direxio-connect"
|
|
58
|
+
|
|
59
|
+
write_state() {
|
|
60
|
+
local state=$1 domain=$2 service_dir=$3
|
|
61
|
+
mkdir -p "$(dirname "$state")" "$service_dir/cc-connect"
|
|
62
|
+
: > "$service_dir/cc-connect/config.toml"
|
|
63
|
+
jq -n \
|
|
64
|
+
--arg region "us-east-1" \
|
|
65
|
+
--arg domain "$domain" \
|
|
66
|
+
--arg service_dir "$service_dir" \
|
|
67
|
+
'{
|
|
68
|
+
region: $region,
|
|
69
|
+
domain_mode: "user",
|
|
70
|
+
domain: $domain,
|
|
71
|
+
as_url: ("https://" + $domain),
|
|
72
|
+
agent_service_dir: $service_dir,
|
|
73
|
+
agent_service_id: $domain,
|
|
74
|
+
resources: {
|
|
75
|
+
instance_id: "i-test",
|
|
76
|
+
eip_id: "eipalloc-test",
|
|
77
|
+
sg_id: "sg-test",
|
|
78
|
+
key_name: "direxio-test"
|
|
79
|
+
}
|
|
80
|
+
}' > "$state"
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
run_destroy() {
|
|
84
|
+
local state=$1 calls=$2 status_work_dir=$3
|
|
85
|
+
: > "$calls"
|
|
86
|
+
CALLS="$calls" STATUS_WORK_DIR="$status_work_dir" PATH="$fakebin:$PATH" bash "$ROOT/scripts/destroy.sh" "$state" >/dev/null
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
current_service="$HOME/.direxio/nodes/a5.direxio.ai"
|
|
90
|
+
current_state="$current_service/state.json"
|
|
91
|
+
current_calls="$tmp/current.calls"
|
|
92
|
+
write_state "$current_state" "a5.direxio.ai" "$current_service"
|
|
93
|
+
run_destroy "$current_state" "$current_calls" "$current_service/cc-connect"
|
|
94
|
+
|
|
95
|
+
grep -q '^direxio-connect daemon status --service-name a5.direxio.ai$' "$current_calls" || {
|
|
96
|
+
echo "destroy should query the current named daemon status" >&2
|
|
97
|
+
cat "$current_calls" >&2
|
|
98
|
+
exit 1
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
grep -q '^direxio-connect daemon stop --service-name a5.direxio.ai$' "$current_calls" || {
|
|
102
|
+
echo "destroy should stop the daemon when daemon status WorkDir matches the current service cc-connect dir" >&2
|
|
103
|
+
cat "$current_calls" >&2
|
|
104
|
+
exit 1
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
grep -q '^direxio-connect daemon uninstall --service-name a5.direxio.ai$' "$current_calls" || {
|
|
108
|
+
echo "destroy should uninstall the daemon after stopping the matching current service daemon" >&2
|
|
109
|
+
cat "$current_calls" >&2
|
|
110
|
+
exit 1
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
if [ -d "$current_service" ]; then
|
|
114
|
+
echo "destroy should remove the current service directory after stopping its daemon" >&2
|
|
115
|
+
exit 1
|
|
116
|
+
fi
|
|
117
|
+
|
|
118
|
+
other_service="$HOME/.direxio/nodes/b5.direxio.ai"
|
|
119
|
+
other_state="$other_service/state.json"
|
|
120
|
+
active_other_service="$HOME/.direxio/nodes/active-other"
|
|
121
|
+
other_calls="$tmp/other.calls"
|
|
122
|
+
mkdir -p "$active_other_service/cc-connect"
|
|
123
|
+
write_state "$other_state" "b5.direxio.ai" "$other_service"
|
|
124
|
+
run_destroy "$other_state" "$other_calls" "$active_other_service/cc-connect"
|
|
125
|
+
|
|
126
|
+
grep -q '^direxio-connect daemon status --service-name b5.direxio.ai$' "$other_calls" || {
|
|
127
|
+
echo "destroy should query the named daemon for the service being destroyed" >&2
|
|
128
|
+
cat "$other_calls" >&2
|
|
129
|
+
exit 1
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
if grep -q '^direxio-connect daemon stop' "$other_calls"; then
|
|
133
|
+
echo "destroy must not stop a daemon whose status WorkDir belongs to a different service" >&2
|
|
134
|
+
cat "$other_calls" >&2
|
|
135
|
+
exit 1
|
|
136
|
+
fi
|
|
137
|
+
|
|
138
|
+
if grep -q '^direxio-connect daemon uninstall' "$other_calls"; then
|
|
139
|
+
echo "destroy must not uninstall a daemon whose status WorkDir belongs to a different service" >&2
|
|
140
|
+
cat "$other_calls" >&2
|
|
141
|
+
exit 1
|
|
142
|
+
fi
|
|
143
|
+
|
|
144
|
+
if [ -d "$other_service" ]; then
|
|
145
|
+
echo "destroy should remove the current service directory even when another service daemon is active" >&2
|
|
146
|
+
exit 1
|
|
147
|
+
fi
|
|
148
|
+
|
|
149
|
+
if [ ! -d "$active_other_service" ]; then
|
|
150
|
+
echo "destroy must not remove another service directory" >&2
|
|
151
|
+
exit 1
|
|
152
|
+
fi
|
|
153
|
+
|
|
154
|
+
echo "destroy local bridge ok"
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
ROOT=$(cd "$(dirname "$0")/.." && pwd)
|
|
5
|
+
tmp=$(mktemp -d)
|
|
6
|
+
trap 'rm -rf "$tmp"' EXIT
|
|
7
|
+
|
|
8
|
+
export HOME="$tmp/home"
|
|
9
|
+
mkdir -p "$HOME"
|
|
10
|
+
|
|
11
|
+
fakebin="$tmp/bin"
|
|
12
|
+
mkdir -p "$fakebin"
|
|
13
|
+
|
|
14
|
+
cat > "$fakebin/aws" <<'EOF'
|
|
15
|
+
#!/usr/bin/env bash
|
|
16
|
+
set -euo pipefail
|
|
17
|
+
printf 'aws' >> "$CALLS"
|
|
18
|
+
printf ' %q' "$@" >> "$CALLS"
|
|
19
|
+
printf '\n' >> "$CALLS"
|
|
20
|
+
|
|
21
|
+
case "${1:-} ${2:-}" in
|
|
22
|
+
"sts get-caller-identity")
|
|
23
|
+
case "$*" in
|
|
24
|
+
*"--query Arn"*) printf 'arn:aws:iam::123456789012:root\n' ;;
|
|
25
|
+
*"--query Account"*) printf '123456789012\n' ;;
|
|
26
|
+
*) printf '{"Account":"123456789012","Arn":"arn:aws:iam::123456789012:root"}\n' ;;
|
|
27
|
+
esac
|
|
28
|
+
;;
|
|
29
|
+
"ec2 terminate-instances"|"ec2 release-address"|"ec2 delete-security-group"|"ec2 delete-key-pair"|"route53 change-resource-record-sets")
|
|
30
|
+
exit 0
|
|
31
|
+
;;
|
|
32
|
+
*)
|
|
33
|
+
exit 0
|
|
34
|
+
;;
|
|
35
|
+
esac
|
|
36
|
+
EOF
|
|
37
|
+
chmod 700 "$fakebin/aws"
|
|
38
|
+
|
|
39
|
+
service_dir="$HOME/.direxio/nodes/root-destroy.example.test"
|
|
40
|
+
mkdir -p "$service_dir"
|
|
41
|
+
state="$service_dir/state.json"
|
|
42
|
+
jq -n \
|
|
43
|
+
--arg service_dir "$service_dir" \
|
|
44
|
+
'{
|
|
45
|
+
region: "us-east-1",
|
|
46
|
+
domain_mode: "user",
|
|
47
|
+
domain: "root-destroy.example.test",
|
|
48
|
+
agent_service_dir: $service_dir,
|
|
49
|
+
agent_service_id: "root-destroy.example.test",
|
|
50
|
+
resources: {
|
|
51
|
+
instance_id: "i-root-destroy",
|
|
52
|
+
eip_id: "eipalloc-root-destroy",
|
|
53
|
+
sg_id: "sg-root-destroy",
|
|
54
|
+
key_name: "direxio-root-destroy"
|
|
55
|
+
}
|
|
56
|
+
}' > "$state"
|
|
57
|
+
|
|
58
|
+
calls="$tmp/aws.calls"
|
|
59
|
+
: > "$calls"
|
|
60
|
+
set +e
|
|
61
|
+
CALLS="$calls" PATH="$fakebin:$PATH" bash "$ROOT/scripts/destroy.sh" "$state" > "$tmp/destroy.out" 2>&1
|
|
62
|
+
destroy_rc=$?
|
|
63
|
+
set -e
|
|
64
|
+
|
|
65
|
+
[ "$destroy_rc" -eq 0 ] || {
|
|
66
|
+
echo "destroy must allow root identity when the operator chose root credentials" >&2
|
|
67
|
+
cat "$tmp/destroy.out" >&2
|
|
68
|
+
exit 1
|
|
69
|
+
}
|
|
70
|
+
grep -q 'source = ' "$tmp/destroy.out"
|
|
71
|
+
|
|
72
|
+
for expected in 'ec2 terminate-instances' 'ec2 release-address' 'ec2 delete-security-group' 'ec2 delete-key-pair'; do
|
|
73
|
+
if ! grep -F "$expected" "$calls" >/dev/null; then
|
|
74
|
+
echo "destroy should process recorded AWS resource with root identity: $expected" >&2
|
|
75
|
+
cat "$calls" >&2
|
|
76
|
+
exit 1
|
|
77
|
+
fi
|
|
78
|
+
done
|
|
79
|
+
|
|
80
|
+
if grep -F 'route53 change-resource-record-sets' "$calls" >/dev/null; then
|
|
81
|
+
echo "destroy should not touch Route53 for DOMAIN_MODE=user" >&2
|
|
82
|
+
cat "$calls" >&2
|
|
83
|
+
exit 1
|
|
84
|
+
fi
|
|
85
|
+
|
|
86
|
+
if [ -d "$service_dir" ]; then
|
|
87
|
+
echo "destroy should remove local service state after processing resources" >&2
|
|
88
|
+
exit 1
|
|
89
|
+
fi
|
|
90
|
+
|
|
91
|
+
echo "destroy root identity allowed ok"
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
ROOT=$(cd "$(dirname "$0")/.." && pwd)
|
|
5
|
+
tmp=$(mktemp -d)
|
|
6
|
+
trap 'rm -rf "$tmp"' EXIT
|
|
7
|
+
|
|
8
|
+
export HOME="$tmp/home"
|
|
9
|
+
mkdir -p "$HOME"
|
|
10
|
+
|
|
11
|
+
fakebin="$tmp/bin"
|
|
12
|
+
mkdir -p "$fakebin"
|
|
13
|
+
cat > "$fakebin/aws" <<'EOF'
|
|
14
|
+
#!/usr/bin/env bash
|
|
15
|
+
set -euo pipefail
|
|
16
|
+
printf 'aws' >> "$CALLS"
|
|
17
|
+
printf ' %q' "$@" >> "$CALLS"
|
|
18
|
+
printf '\n' >> "$CALLS"
|
|
19
|
+
|
|
20
|
+
case "${1:-} ${2:-}" in
|
|
21
|
+
"sts get-caller-identity")
|
|
22
|
+
case "$*" in
|
|
23
|
+
*"--query Arn"*) printf 'arn:aws:iam::123456789012:user/DirexioDeployer-Test\n' ;;
|
|
24
|
+
*"--query Account"*) printf '123456789012\n' ;;
|
|
25
|
+
*) printf '{"Account":"123456789012","Arn":"arn:aws:iam::123456789012:user/DirexioDeployer-Test"}\n' ;;
|
|
26
|
+
esac
|
|
27
|
+
;;
|
|
28
|
+
"route53 list-hosted-zones")
|
|
29
|
+
printf '{"HostedZones":[{"Id":"/hostedzone/ZCREATE","Name":"route53-destroy.example.test."}]}\n'
|
|
30
|
+
;;
|
|
31
|
+
"route53 change-resource-record-sets")
|
|
32
|
+
exit 0
|
|
33
|
+
;;
|
|
34
|
+
"route53 delete-hosted-zone")
|
|
35
|
+
exit 0
|
|
36
|
+
;;
|
|
37
|
+
"ec2 terminate-instances"|"ec2 wait"|"ec2 release-address"|"ec2 delete-security-group"|"ec2 delete-key-pair")
|
|
38
|
+
exit 0
|
|
39
|
+
;;
|
|
40
|
+
*)
|
|
41
|
+
exit 0
|
|
42
|
+
;;
|
|
43
|
+
esac
|
|
44
|
+
EOF
|
|
45
|
+
chmod 700 "$fakebin/aws"
|
|
46
|
+
|
|
47
|
+
service_dir="$HOME/.direxio/nodes/route53-destroy.example.test"
|
|
48
|
+
mkdir -p "$service_dir"
|
|
49
|
+
state="$service_dir/state.json"
|
|
50
|
+
jq -n \
|
|
51
|
+
--arg service_dir "$service_dir" \
|
|
52
|
+
'{
|
|
53
|
+
region: "us-east-1",
|
|
54
|
+
domain_mode: "route53",
|
|
55
|
+
domain: "route53-destroy.example.test",
|
|
56
|
+
agent_service_dir: $service_dir,
|
|
57
|
+
resources: {
|
|
58
|
+
public_ip: "203.0.113.99",
|
|
59
|
+
route53_zone_id: "ZCREATE",
|
|
60
|
+
route53_zone_name: "route53-destroy.example.test",
|
|
61
|
+
route53_zone_created_by_deployer: "true"
|
|
62
|
+
}
|
|
63
|
+
}' > "$state"
|
|
64
|
+
|
|
65
|
+
calls="$tmp/aws.calls"
|
|
66
|
+
CALLS="$calls" PATH="$fakebin:$PATH" bash "$ROOT/scripts/destroy.sh" "$state" >/dev/null
|
|
67
|
+
|
|
68
|
+
grep -q '^aws route53 change-resource-record-sets --hosted-zone-id ZCREATE' "$calls" || {
|
|
69
|
+
echo "destroy should delete the Route53 A record from the recorded zone" >&2
|
|
70
|
+
cat "$calls" >&2
|
|
71
|
+
exit 1
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
grep -q '^aws route53 delete-hosted-zone --id ZCREATE$' "$calls" || {
|
|
75
|
+
echo "destroy should delete a deployer-created hosted zone to stop Route53 hosted-zone billing" >&2
|
|
76
|
+
cat "$calls" >&2
|
|
77
|
+
exit 1
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
echo "destroy route53 zone ok"
|