mirror of
https://github.com/harivansh-afk/betterNAS.git
synced 2026-04-15 09:01:13 +00:00
setup agent runtime requirements
This commit is contained in:
parent
5d97c33d7e
commit
016e0ee581
17 changed files with 424 additions and 28 deletions
12
.env.agent.example
Normal file
12
.env.agent.example
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
BETTERNAS_CLONE_NAME=betternas-main
|
||||||
|
COMPOSE_PROJECT_NAME=betternas-main
|
||||||
|
BETTERNAS_CONTROL_PLANE_PORT=3001
|
||||||
|
BETTERNAS_NODE_AGENT_PORT=3090
|
||||||
|
BETTERNAS_NEXTCLOUD_PORT=8080
|
||||||
|
BETTERNAS_EXPORT_PATH=.state/betternas-main/export
|
||||||
|
BETTERNAS_VERSION=local-dev
|
||||||
|
BETTERNAS_NODE_DIRECT_ADDRESS=http://localhost:${BETTERNAS_NODE_AGENT_PORT}
|
||||||
|
BETTERNAS_EXAMPLE_MOUNT_URL=http://localhost:${BETTERNAS_NODE_AGENT_PORT}/dav/
|
||||||
|
NEXTCLOUD_BASE_URL=http://localhost:${BETTERNAS_NEXTCLOUD_PORT}
|
||||||
|
NEXTCLOUD_ADMIN_USER=admin
|
||||||
|
NEXTCLOUD_ADMIN_PASSWORD=admin
|
||||||
22
README.md
22
README.md
|
|
@ -15,7 +15,7 @@
|
||||||
- `packages/ui`: shared React UI
|
- `packages/ui`: shared React UI
|
||||||
- `infra/docker`: local Docker runtime
|
- `infra/docker`: local Docker runtime
|
||||||
|
|
||||||
The root planning and delegation guide lives in [skeleton.md](/home/rathi/Documents/GitHub/betterNAS/skeleton.md).
|
The root planning and delegation guide lives in [skeleton.md](./skeleton.md).
|
||||||
|
|
||||||
## Verify
|
## Verify
|
||||||
|
|
||||||
|
|
@ -24,3 +24,23 @@ Run the repo acceptance loop with:
|
||||||
```bash
|
```bash
|
||||||
pnpm verify
|
pnpm verify
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Agent loop
|
||||||
|
|
||||||
|
Bootstrap a clone-local environment with:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pnpm agent:bootstrap
|
||||||
|
```
|
||||||
|
|
||||||
|
Run the full static and integration loop with:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pnpm agent:verify
|
||||||
|
```
|
||||||
|
|
||||||
|
Create or refresh the sibling agent clones with:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pnpm clones:setup
|
||||||
|
```
|
||||||
|
|
|
||||||
|
|
@ -12,4 +12,4 @@ It is intentionally small for now:
|
||||||
- `POST /api/v1/cloud-profiles/issue`
|
- `POST /api/v1/cloud-profiles/issue`
|
||||||
|
|
||||||
The request and response shapes must follow the contracts in
|
The request and response shapes must follow the contracts in
|
||||||
[`packages/contracts`](/home/rathi/Documents/GitHub/betterNAS/packages/contracts).
|
[`packages/contracts`](../../packages/contracts).
|
||||||
|
|
|
||||||
15
apps/node-agent/Dockerfile
Normal file
15
apps/node-agent/Dockerfile
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
FROM golang:1.26-alpine AS build
|
||||||
|
|
||||||
|
WORKDIR /src
|
||||||
|
COPY apps/node-agent ./apps/node-agent
|
||||||
|
|
||||||
|
WORKDIR /src/apps/node-agent
|
||||||
|
RUN CGO_ENABLED=0 GOOS=linux go build -o /out/node-agent ./cmd/node-agent
|
||||||
|
|
||||||
|
FROM alpine:3.21
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
COPY --from=build /out/node-agent /usr/local/bin/node-agent
|
||||||
|
|
||||||
|
EXPOSE 8090
|
||||||
|
CMD ["node-agent"]
|
||||||
45
control.md
Normal file
45
control.md
Normal file
|
|
@ -0,0 +1,45 @@
|
||||||
|
# Control
|
||||||
|
|
||||||
|
This clone is the main repo.
|
||||||
|
|
||||||
|
Use it for:
|
||||||
|
|
||||||
|
- shared contracts
|
||||||
|
- repo guardrails
|
||||||
|
- runtime scripts
|
||||||
|
- integration verification
|
||||||
|
- architecture and coordination
|
||||||
|
|
||||||
|
Planned clone layout:
|
||||||
|
|
||||||
|
```text
|
||||||
|
/home/rathi/Documents/GitHub/betterNAS/
|
||||||
|
betterNAS
|
||||||
|
betterNAS-runtime
|
||||||
|
betterNAS-control
|
||||||
|
betterNAS-node
|
||||||
|
```
|
||||||
|
|
||||||
|
Clone roles:
|
||||||
|
|
||||||
|
- `betterNAS`
|
||||||
|
- main coordination repo
|
||||||
|
- owns contracts, scripts, and shared verification rules
|
||||||
|
- `betterNAS-runtime`
|
||||||
|
- owns Docker Compose, stack env, readiness checks, and end-to-end runtime verification
|
||||||
|
- `betterNAS-control`
|
||||||
|
- owns the Go control plane and contract-backed API behavior
|
||||||
|
- `betterNAS-node`
|
||||||
|
- owns the node agent, WebDAV serving, and NAS-side registration/export behavior
|
||||||
|
|
||||||
|
Rules:
|
||||||
|
|
||||||
|
- shared interface changes land in `packages/contracts` first
|
||||||
|
- runtime verification must stay green in the main repo
|
||||||
|
- feature agents should stay inside their assigned clone unless a contract change is required
|
||||||
|
|
||||||
|
Agent command surface:
|
||||||
|
|
||||||
|
- main repo creates or refreshes sibling clones with `pnpm clones:setup`
|
||||||
|
- each clone bootstraps itself with `pnpm agent:bootstrap`
|
||||||
|
- each clone runs the full loop with `pnpm agent:verify`
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
This file is the canonical contract for the repository.
|
This file is the canonical contract for the repository.
|
||||||
|
|
||||||
If the planning docs, scaffold code, or future tasks disagree, this file and
|
If the planning docs, scaffold code, or future tasks disagree, this file and
|
||||||
[`packages/contracts`](/home/rathi/Documents/GitHub/betterNAS/packages/contracts)
|
[`packages/contracts`](../packages/contracts)
|
||||||
win.
|
win.
|
||||||
|
|
||||||
## The single first task
|
## The single first task
|
||||||
|
|
@ -63,26 +63,26 @@ parallelized without interface drift.
|
||||||
|
|
||||||
Use these in this order:
|
Use these in this order:
|
||||||
|
|
||||||
1. [`docs/architecture.md`](/home/rathi/Documents/GitHub/betterNAS/docs/architecture.md)
|
1. [`docs/architecture.md`](./architecture.md)
|
||||||
for boundaries, ownership, and delivery rules
|
for boundaries, ownership, and delivery rules
|
||||||
2. [`packages/contracts`](/home/rathi/Documents/GitHub/betterNAS/packages/contracts)
|
2. [`packages/contracts`](../packages/contracts)
|
||||||
for machine-readable types, schemas, and route constants
|
for machine-readable types, schemas, and route constants
|
||||||
3. the part docs for local detail:
|
3. the part docs for local detail:
|
||||||
- [`docs/01-nas-node.md`](/home/rathi/Documents/GitHub/betterNAS/docs/01-nas-node.md)
|
- [`docs/01-nas-node.md`](./01-nas-node.md)
|
||||||
- [`docs/02-control-plane.md`](/home/rathi/Documents/GitHub/betterNAS/docs/02-control-plane.md)
|
- [`docs/02-control-plane.md`](./02-control-plane.md)
|
||||||
- [`docs/03-local-device.md`](/home/rathi/Documents/GitHub/betterNAS/docs/03-local-device.md)
|
- [`docs/03-local-device.md`](./03-local-device.md)
|
||||||
- [`docs/04-cloud-web-layer.md`](/home/rathi/Documents/GitHub/betterNAS/docs/04-cloud-web-layer.md)
|
- [`docs/04-cloud-web-layer.md`](./04-cloud-web-layer.md)
|
||||||
- [`docs/05-build-plan.md`](/home/rathi/Documents/GitHub/betterNAS/docs/05-build-plan.md)
|
- [`docs/05-build-plan.md`](./05-build-plan.md)
|
||||||
|
|
||||||
## Repo lanes
|
## Repo lanes
|
||||||
|
|
||||||
The monorepo is split into these primary implementation lanes:
|
The monorepo is split into these primary implementation lanes:
|
||||||
|
|
||||||
- [`apps/node-agent`](/home/rathi/Documents/GitHub/betterNAS/apps/node-agent)
|
- [`apps/node-agent`](../apps/node-agent)
|
||||||
- [`apps/control-plane`](/home/rathi/Documents/GitHub/betterNAS/apps/control-plane)
|
- [`apps/control-plane`](../apps/control-plane)
|
||||||
- [`apps/web`](/home/rathi/Documents/GitHub/betterNAS/apps/web)
|
- [`apps/web`](../apps/web)
|
||||||
- [`apps/nextcloud-app`](/home/rathi/Documents/GitHub/betterNAS/apps/nextcloud-app)
|
- [`apps/nextcloud-app`](../apps/nextcloud-app)
|
||||||
- [`packages/contracts`](/home/rathi/Documents/GitHub/betterNAS/packages/contracts)
|
- [`packages/contracts`](../packages/contracts)
|
||||||
|
|
||||||
Every parallel task should primarily stay inside one of those lanes unless it is
|
Every parallel task should primarily stay inside one of those lanes unless it is
|
||||||
an explicit contract task.
|
an explicit contract task.
|
||||||
|
|
@ -132,7 +132,7 @@ Each area gets an owner and a narrow write surface.
|
||||||
|
|
||||||
The only shared write surface across teams should be:
|
The only shared write surface across teams should be:
|
||||||
|
|
||||||
- [`packages/contracts`](/home/rathi/Documents/GitHub/betterNAS/packages/contracts)
|
- [`packages/contracts`](../packages/contracts)
|
||||||
- this file when the architecture contract changes
|
- this file when the architecture contract changes
|
||||||
|
|
||||||
## Verification loop
|
## Verification loop
|
||||||
|
|
@ -165,7 +165,7 @@ The initial scaffold is complete when:
|
||||||
|
|
||||||
1. No part may invent private request or response shapes for shared flows.
|
1. No part may invent private request or response shapes for shared flows.
|
||||||
2. Contract changes must update
|
2. Contract changes must update
|
||||||
[`packages/contracts`](/home/rathi/Documents/GitHub/betterNAS/packages/contracts)
|
[`packages/contracts`](../packages/contracts)
|
||||||
first.
|
first.
|
||||||
3. Architecture changes must update this file in the same change.
|
3. Architecture changes must update this file in the same change.
|
||||||
4. Additive contract changes are preferred over breaking ones.
|
4. Additive contract changes are preferred over breaking ones.
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,8 @@
|
||||||
"stack:up": "./scripts/dev-up",
|
"stack:up": "./scripts/dev-up",
|
||||||
"stack:down": "./scripts/dev-down",
|
"stack:down": "./scripts/dev-down",
|
||||||
"stack:verify": "./scripts/integration/verify-stack",
|
"stack:verify": "./scripts/integration/verify-stack",
|
||||||
|
"agent:bootstrap": "./scripts/agent-bootstrap",
|
||||||
|
"agent:verify": "./scripts/agent-verify",
|
||||||
"clones:setup": "./scripts/setup-clones",
|
"clones:setup": "./scripts/setup-clones",
|
||||||
"test": "turbo run test",
|
"test": "turbo run test",
|
||||||
"verify": "pnpm run guardrails && pnpm run format:check && turbo run lint check-types test build"
|
"verify": "pnpm run guardrails && pnpm run format:check && turbo run lint check-types test build"
|
||||||
|
|
|
||||||
|
|
@ -25,20 +25,20 @@ Use it to keep the four product parts aligned:
|
||||||
|
|
||||||
## Current contract layers
|
## Current contract layers
|
||||||
|
|
||||||
- [`src/control-plane.ts`](/home/rathi/Documents/GitHub/betterNAS/packages/contracts/src/control-plane.ts)
|
- [`src/control-plane.ts`](./src/control-plane.ts)
|
||||||
- current runtime scaffold for health and version
|
- current runtime scaffold for health and version
|
||||||
- [`src/foundation.ts`](/home/rathi/Documents/GitHub/betterNAS/packages/contracts/src/foundation.ts)
|
- [`src/foundation.ts`](./src/foundation.ts)
|
||||||
- first product-level entities and route constants for node, mount, and cloud flows
|
- first product-level entities and route constants for node, mount, and cloud flows
|
||||||
- [`openapi/`](/home/rathi/Documents/GitHub/betterNAS/packages/contracts/openapi)
|
- [`openapi/`](./openapi)
|
||||||
- language-neutral source documents for future SDK generation
|
- language-neutral source documents for future SDK generation
|
||||||
- [`schemas/`](/home/rathi/Documents/GitHub/betterNAS/packages/contracts/schemas)
|
- [`schemas/`](./schemas)
|
||||||
- JSON schema mirrors for the first shared entities
|
- JSON schema mirrors for the first shared entities
|
||||||
|
|
||||||
## Change rules
|
## Change rules
|
||||||
|
|
||||||
1. Shared API shape changes happen here first.
|
1. Shared API shape changes happen here first.
|
||||||
2. If the boundary changes, also update
|
2. If the boundary changes, also update
|
||||||
[`docs/architecture.md`](/home/rathi/Documents/GitHub/betterNAS/docs/architecture.md).
|
[`docs/architecture.md`](../../docs/architecture.md).
|
||||||
3. Prefer additive changes until all four parts are live.
|
3. Prefer additive changes until all four parts are live.
|
||||||
4. Do not put Nextcloud-only assumptions into the core contracts unless the
|
4. Do not put Nextcloud-only assumptions into the core contracts unless the
|
||||||
field is explicitly part of the cloud adapter.
|
field is explicitly part of the cloud adapter.
|
||||||
|
|
|
||||||
43
scripts/agent-bootstrap
Executable file
43
scripts/agent-bootstrap
Executable file
|
|
@ -0,0 +1,43 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
repo_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||||
|
env_file="$repo_root/.env.agent"
|
||||||
|
example_env_file="$repo_root/.env.agent.example"
|
||||||
|
|
||||||
|
if [[ ! -f "$env_file" ]]; then
|
||||||
|
cp "$example_env_file" "$env_file"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# shellcheck disable=SC1091
|
||||||
|
source "$repo_root/scripts/lib/runtime-env.sh"
|
||||||
|
|
||||||
|
mkdir -p "$BETTERNAS_EXPORT_PATH"
|
||||||
|
|
||||||
|
if [[ ! -f "$BETTERNAS_EXPORT_PATH/README.txt" ]]; then
|
||||||
|
cat >"$BETTERNAS_EXPORT_PATH/README.txt" <<EOF
|
||||||
|
betterNAS export
|
||||||
|
clone=${BETTERNAS_CLONE_NAME}
|
||||||
|
mount_url=${BETTERNAS_EXAMPLE_MOUNT_URL}
|
||||||
|
EOF
|
||||||
|
fi
|
||||||
|
|
||||||
|
pnpm install --frozen-lockfile
|
||||||
|
go work sync
|
||||||
|
|
||||||
|
cat <<EOF
|
||||||
|
Agent bootstrap complete for ${BETTERNAS_CLONE_NAME}
|
||||||
|
|
||||||
|
Env file: ${env_file}
|
||||||
|
Control plane: http://localhost:${BETTERNAS_CONTROL_PLANE_PORT}
|
||||||
|
Node agent: http://localhost:${BETTERNAS_NODE_AGENT_PORT}
|
||||||
|
Nextcloud: ${NEXTCLOUD_BASE_URL}
|
||||||
|
Export path: ${BETTERNAS_EXPORT_PATH}
|
||||||
|
Mount URL: ${BETTERNAS_EXAMPLE_MOUNT_URL}
|
||||||
|
|
||||||
|
Next:
|
||||||
|
pnpm verify
|
||||||
|
pnpm stack:up
|
||||||
|
pnpm stack:verify
|
||||||
|
EOF
|
||||||
11
scripts/agent-verify
Executable file
11
scripts/agent-verify
Executable file
|
|
@ -0,0 +1,11 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
repo_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||||
|
|
||||||
|
cd "$repo_root"
|
||||||
|
./scripts/agent-bootstrap
|
||||||
|
pnpm verify
|
||||||
|
./scripts/dev-up
|
||||||
|
./scripts/integration/verify-stack
|
||||||
54
scripts/integration/verify-stack
Executable file
54
scripts/integration/verify-stack
Executable file
|
|
@ -0,0 +1,54 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
# shellcheck disable=SC1091
|
||||||
|
source "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/../lib/runtime-env.sh"
|
||||||
|
|
||||||
|
"$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/wait-stack"
|
||||||
|
"$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/verify-webdav"
|
||||||
|
|
||||||
|
control_health="$(curl -fsS "http://localhost:${BETTERNAS_CONTROL_PLANE_PORT}/health")"
|
||||||
|
echo "$control_health" | jq -e '.service == "control-plane" and .status == "ok"' >/dev/null
|
||||||
|
|
||||||
|
register_response="$(
|
||||||
|
curl -fsS \
|
||||||
|
-X POST \
|
||||||
|
-H 'Content-Type: application/json' \
|
||||||
|
-d @- \
|
||||||
|
"http://localhost:${BETTERNAS_CONTROL_PLANE_PORT}/api/v1/nodes/register" <<JSON
|
||||||
|
{"machineId":"${BETTERNAS_CLONE_NAME}-machine","displayName":"${BETTERNAS_CLONE_NAME} node","agentVersion":"${BETTERNAS_VERSION}","directAddress":"${BETTERNAS_NODE_DIRECT_ADDRESS}","relayAddress":null,"exports":[{"label":"integration","path":"${BETTERNAS_EXPORT_PATH}","protocols":["webdav"],"capacityBytes":null,"tags":["integration"]}]}
|
||||||
|
JSON
|
||||||
|
)"
|
||||||
|
echo "$register_response" | jq -e '.status == "online"' >/dev/null
|
||||||
|
|
||||||
|
mount_profile="$(
|
||||||
|
curl -fsS \
|
||||||
|
-X POST \
|
||||||
|
-H 'Content-Type: application/json' \
|
||||||
|
-d '{"userId":"integration-user","deviceId":"integration-device","exportId":"dev-export"}' \
|
||||||
|
"http://localhost:${BETTERNAS_CONTROL_PLANE_PORT}/api/v1/mount-profiles/issue"
|
||||||
|
)"
|
||||||
|
echo "$mount_profile" | jq -e --arg expected "$BETTERNAS_EXAMPLE_MOUNT_URL" '.protocol == "webdav" and .mountUrl == $expected' >/dev/null
|
||||||
|
|
||||||
|
cloud_profile="$(
|
||||||
|
curl -fsS \
|
||||||
|
-X POST \
|
||||||
|
-H 'Content-Type: application/json' \
|
||||||
|
-d '{"userId":"integration-user","exportId":"dev-export","provider":"nextcloud"}' \
|
||||||
|
"http://localhost:${BETTERNAS_CONTROL_PLANE_PORT}/api/v1/cloud-profiles/issue"
|
||||||
|
)"
|
||||||
|
echo "$cloud_profile" | jq -e --arg expected "$NEXTCLOUD_BASE_URL" '.provider == "nextcloud" and .baseUrl == $expected' >/dev/null
|
||||||
|
|
||||||
|
nextcloud_status="$(curl -fsS "${NEXTCLOUD_BASE_URL}/status.php")"
|
||||||
|
echo "$nextcloud_status" | jq -e '.installed == true' >/dev/null
|
||||||
|
|
||||||
|
nextcloud_app_status="$(
|
||||||
|
curl -fsS \
|
||||||
|
-u "${NEXTCLOUD_ADMIN_USER}:${NEXTCLOUD_ADMIN_PASSWORD}" \
|
||||||
|
-H 'OCS-APIRequest: true' \
|
||||||
|
"${NEXTCLOUD_BASE_URL}/ocs/v2.php/apps/betternascontrolplane/api/status"
|
||||||
|
)"
|
||||||
|
echo "$nextcloud_app_status" | jq -e '.ocs.meta.statuscode == 100' >/dev/null
|
||||||
|
|
||||||
|
echo "Stack verified for ${BETTERNAS_CLONE_NAME}."
|
||||||
19
scripts/integration/verify-webdav
Executable file
19
scripts/integration/verify-webdav
Executable file
|
|
@ -0,0 +1,19 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
# shellcheck disable=SC1091
|
||||||
|
source "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/../lib/runtime-env.sh"
|
||||||
|
|
||||||
|
headers="$(mktemp)"
|
||||||
|
trap 'rm -f "$headers"' EXIT
|
||||||
|
|
||||||
|
curl -fsS -D "$headers" -o /dev/null -X PROPFIND -H 'Depth: 0' "$BETTERNAS_EXAMPLE_MOUNT_URL"
|
||||||
|
|
||||||
|
if ! grep -Eq '^HTTP/[0-9.]+ 207' "$headers"; then
|
||||||
|
echo "WebDAV PROPFIND did not return 207 for $BETTERNAS_EXAMPLE_MOUNT_URL" >&2
|
||||||
|
cat "$headers" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "WebDAV verified: $BETTERNAS_EXAMPLE_MOUNT_URL"
|
||||||
27
scripts/integration/wait-stack
Executable file
27
scripts/integration/wait-stack
Executable file
|
|
@ -0,0 +1,27 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
# shellcheck disable=SC1091
|
||||||
|
source "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/../lib/runtime-env.sh"
|
||||||
|
|
||||||
|
wait_for_url() {
|
||||||
|
local url="$1"
|
||||||
|
local label="$2"
|
||||||
|
local max_attempts="${3:-60}"
|
||||||
|
|
||||||
|
for _ in $(seq 1 "$max_attempts"); do
|
||||||
|
if curl -fsS "$url" >/dev/null 2>&1; then
|
||||||
|
echo "$label ready: $url"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
sleep 2
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "$label did not become ready: $url" >&2
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
wait_for_url "http://localhost:${BETTERNAS_CONTROL_PLANE_PORT}/health" "control plane"
|
||||||
|
wait_for_url "http://localhost:${BETTERNAS_NODE_AGENT_PORT}/health" "node agent"
|
||||||
|
wait_for_url "${NEXTCLOUD_BASE_URL}/status.php" "nextcloud"
|
||||||
58
scripts/lib/runtime-env.sh
Executable file
58
scripts/lib/runtime-env.sh
Executable file
|
|
@ -0,0 +1,58 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
repo_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
|
||||||
|
compose_file="$repo_root/infra/docker/compose.dev.yml"
|
||||||
|
default_env_file="$repo_root/.env.agent"
|
||||||
|
env_file="${BETTERNAS_ENV_FILE:-$default_env_file}"
|
||||||
|
|
||||||
|
if [[ -f "$env_file" ]]; then
|
||||||
|
set -a
|
||||||
|
# shellcheck disable=SC1090
|
||||||
|
source "$env_file"
|
||||||
|
set +a
|
||||||
|
fi
|
||||||
|
|
||||||
|
: "${BETTERNAS_CLONE_NAME:=betternas-main}"
|
||||||
|
: "${COMPOSE_PROJECT_NAME:=betternas-${BETTERNAS_CLONE_NAME}}"
|
||||||
|
: "${BETTERNAS_CONTROL_PLANE_PORT:=3001}"
|
||||||
|
: "${BETTERNAS_NODE_AGENT_PORT:=3090}"
|
||||||
|
: "${BETTERNAS_NEXTCLOUD_PORT:=8080}"
|
||||||
|
: "${BETTERNAS_VERSION:=local-dev}"
|
||||||
|
: "${NEXTCLOUD_ADMIN_USER:=admin}"
|
||||||
|
: "${NEXTCLOUD_ADMIN_PASSWORD:=admin}"
|
||||||
|
|
||||||
|
if [[ -z "${BETTERNAS_EXPORT_PATH:-}" ]]; then
|
||||||
|
BETTERNAS_EXPORT_PATH="$repo_root/.state/$BETTERNAS_CLONE_NAME/export"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "$BETTERNAS_EXPORT_PATH" != /* ]]; then
|
||||||
|
BETTERNAS_EXPORT_PATH="$repo_root/$BETTERNAS_EXPORT_PATH"
|
||||||
|
fi
|
||||||
|
|
||||||
|
: "${BETTERNAS_NODE_DIRECT_ADDRESS:=http://localhost:${BETTERNAS_NODE_AGENT_PORT}}"
|
||||||
|
: "${BETTERNAS_EXAMPLE_MOUNT_URL:=http://localhost:${BETTERNAS_NODE_AGENT_PORT}/dav/}"
|
||||||
|
: "${NEXTCLOUD_BASE_URL:=http://localhost:${BETTERNAS_NEXTCLOUD_PORT}}"
|
||||||
|
|
||||||
|
export repo_root
|
||||||
|
export compose_file
|
||||||
|
export env_file
|
||||||
|
export BETTERNAS_CLONE_NAME
|
||||||
|
export COMPOSE_PROJECT_NAME
|
||||||
|
export BETTERNAS_CONTROL_PLANE_PORT
|
||||||
|
export BETTERNAS_NODE_AGENT_PORT
|
||||||
|
export BETTERNAS_NEXTCLOUD_PORT
|
||||||
|
export BETTERNAS_EXPORT_PATH
|
||||||
|
export BETTERNAS_VERSION
|
||||||
|
export NEXTCLOUD_ADMIN_USER
|
||||||
|
export NEXTCLOUD_ADMIN_PASSWORD
|
||||||
|
export BETTERNAS_NODE_DIRECT_ADDRESS
|
||||||
|
export BETTERNAS_EXAMPLE_MOUNT_URL
|
||||||
|
export NEXTCLOUD_BASE_URL
|
||||||
|
|
||||||
|
mkdir -p "$BETTERNAS_EXPORT_PATH"
|
||||||
|
|
||||||
|
compose() {
|
||||||
|
docker compose -f "$compose_file" "$@"
|
||||||
|
}
|
||||||
51
scripts/setup-clones
Executable file
51
scripts/setup-clones
Executable file
|
|
@ -0,0 +1,51 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
repo_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||||
|
parent_dir="$(cd "$repo_root/.." && pwd)"
|
||||||
|
repo_name="$(basename "$repo_root")"
|
||||||
|
sync_clone_script="$repo_root/scripts/sync-clone"
|
||||||
|
|
||||||
|
declare -A clone_ports=(
|
||||||
|
["betterNAS-runtime"]="41080 41090 41001"
|
||||||
|
["betterNAS-control"]="42080 42090 42001"
|
||||||
|
["betterNAS-node"]="43080 43090 43001"
|
||||||
|
)
|
||||||
|
clone_names=("betterNAS-runtime" "betterNAS-control" "betterNAS-node")
|
||||||
|
|
||||||
|
for clone_name in "${clone_names[@]}"; do
|
||||||
|
clone_dir="$parent_dir/$clone_name"
|
||||||
|
|
||||||
|
"$sync_clone_script" "$clone_dir"
|
||||||
|
|
||||||
|
read -r nextcloud_port node_agent_port control_plane_port <<<"${clone_ports[$clone_name]}"
|
||||||
|
|
||||||
|
cat >"$clone_dir/.env.agent" <<EOF
|
||||||
|
BETTERNAS_CLONE_NAME=${clone_name}
|
||||||
|
COMPOSE_PROJECT_NAME=${clone_name}
|
||||||
|
BETTERNAS_NEXTCLOUD_PORT=${nextcloud_port}
|
||||||
|
BETTERNAS_NODE_AGENT_PORT=${node_agent_port}
|
||||||
|
BETTERNAS_CONTROL_PLANE_PORT=${control_plane_port}
|
||||||
|
BETTERNAS_EXPORT_PATH=.state/${clone_name}/export
|
||||||
|
BETTERNAS_VERSION=local-dev
|
||||||
|
BETTERNAS_NODE_DIRECT_ADDRESS=http://localhost:${node_agent_port}
|
||||||
|
BETTERNAS_EXAMPLE_MOUNT_URL=http://localhost:${node_agent_port}/dav/
|
||||||
|
NEXTCLOUD_BASE_URL=http://localhost:${nextcloud_port}
|
||||||
|
NEXTCLOUD_ADMIN_USER=admin
|
||||||
|
NEXTCLOUD_ADMIN_PASSWORD=admin
|
||||||
|
EOF
|
||||||
|
done
|
||||||
|
|
||||||
|
cat <<EOF
|
||||||
|
Clone setup complete under ${parent_dir}
|
||||||
|
|
||||||
|
Main repo: ${repo_name}
|
||||||
|
Runtime clone: ${parent_dir}/betterNAS-runtime
|
||||||
|
Control clone: ${parent_dir}/betterNAS-control
|
||||||
|
Node clone: ${parent_dir}/betterNAS-node
|
||||||
|
|
||||||
|
Next in each clone:
|
||||||
|
pnpm agent:bootstrap
|
||||||
|
pnpm agent:verify
|
||||||
|
EOF
|
||||||
39
scripts/sync-clone
Executable file
39
scripts/sync-clone
Executable file
|
|
@ -0,0 +1,39 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
repo_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||||
|
|
||||||
|
if [[ $# -ne 1 ]]; then
|
||||||
|
echo "usage: $0 /absolute/path/to/clone" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
clone_dir="$1"
|
||||||
|
|
||||||
|
if [[ "$clone_dir" != /* ]]; then
|
||||||
|
echo "clone path must be absolute: $clone_dir" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ ! -d "$clone_dir/.git" ]]; then
|
||||||
|
git clone --local --no-hardlinks "$repo_root" "$clone_dir"
|
||||||
|
fi
|
||||||
|
|
||||||
|
find "$clone_dir" -mindepth 1 -maxdepth 1 \
|
||||||
|
! -name .git \
|
||||||
|
! -name .env.agent \
|
||||||
|
-exec rm -rf {} +
|
||||||
|
|
||||||
|
tar \
|
||||||
|
--exclude=.git \
|
||||||
|
--exclude=.state \
|
||||||
|
--exclude=.turbo \
|
||||||
|
--exclude=node_modules \
|
||||||
|
--exclude=dist \
|
||||||
|
--exclude='apps/web/.next' \
|
||||||
|
-C "$repo_root" \
|
||||||
|
-cf - \
|
||||||
|
. | tar -C "$clone_dir" -xf -
|
||||||
|
|
||||||
|
echo "Synced working tree into $clone_dir"
|
||||||
12
skeleton.md
12
skeleton.md
|
|
@ -35,8 +35,8 @@ betterNAS/
|
||||||
|
|
||||||
## Runtime and language choices
|
## Runtime and language choices
|
||||||
|
|
||||||
| Part | Language | Why |
|
| Part | Language | Why |
|
||||||
| ------------------ | ---------------------------------- | -------------------------------------------------------------------- |
|
| -------------------- | ---------------------------------- | -------------------------------------------------------------------- |
|
||||||
| `apps/web` | TypeScript + Next.js | best UI velocity, best admin/control-plane UX |
|
| `apps/web` | TypeScript + Next.js | best UI velocity, best admin/control-plane UX |
|
||||||
| `apps/control-plane` | Go | strong concurrency, static binaries, operationally simple |
|
| `apps/control-plane` | Go | strong concurrency, static binaries, operationally simple |
|
||||||
| `apps/node-agent` | Go | best fit for host runtime, WebDAV service, and future Nix deployment |
|
| `apps/node-agent` | Go | best fit for host runtime, WebDAV service, and future Nix deployment |
|
||||||
|
|
@ -47,10 +47,10 @@ betterNAS/
|
||||||
|
|
||||||
The source of truth for shared interfaces is:
|
The source of truth for shared interfaces is:
|
||||||
|
|
||||||
1. [`docs/architecture.md`](/home/rathi/Documents/GitHub/betterNAS/docs/architecture.md)
|
1. [`docs/architecture.md`](./docs/architecture.md)
|
||||||
2. [`packages/contracts/openapi/betternas.v1.yaml`](/home/rathi/Documents/GitHub/betterNAS/packages/contracts/openapi/betternas.v1.yaml)
|
2. [`packages/contracts/openapi/betternas.v1.yaml`](./packages/contracts/openapi/betternas.v1.yaml)
|
||||||
3. [`packages/contracts/schemas`](/home/rathi/Documents/GitHub/betterNAS/packages/contracts/schemas)
|
3. [`packages/contracts/schemas`](./packages/contracts/schemas)
|
||||||
4. [`packages/contracts/src`](/home/rathi/Documents/GitHub/betterNAS/packages/contracts/src)
|
4. [`packages/contracts/src`](./packages/contracts/src)
|
||||||
|
|
||||||
Agents must not invent private shared request or response shapes outside those
|
Agents must not invent private shared request or response shapes outside those
|
||||||
locations.
|
locations.
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue