mirror of
https://github.com/mulgadc/spinifex.git
synced 2026-10-15 17:11:30 +00:00
Merge branch 'feat/iso-installer' of github.com:mulgadc/spinifex into feat/iso-installer
This commit is contained in:
@@ -26,7 +26,7 @@ env:
|
||||
jobs:
|
||||
e2e_single:
|
||||
name: Single-Node E2E
|
||||
runs-on: [self-hosted, ci-single]
|
||||
runs-on: [ self-hosted, ci-single ]
|
||||
timeout-minutes: 30
|
||||
env:
|
||||
TOFU_LOG: /tmp/e2e-tofu-single-${{ github.run_id }}.log
|
||||
@@ -41,14 +41,29 @@ jobs:
|
||||
private-key: ${{ secrets.APP_PRIVATE_KEY }}
|
||||
repositories: mulga
|
||||
|
||||
- name: Resolve Mulga Branch
|
||||
id: mulga-branch
|
||||
env:
|
||||
GH_TOKEN: ${{ steps.app-token.outputs.token }}
|
||||
BRANCH: ${{ github.ref_name }}
|
||||
run: |
|
||||
if gh api "repos/mulgadc/mulga/branches/${BRANCH}" >/dev/null 2>&1; then
|
||||
echo "ref=${BRANCH}" >> "$GITHUB_OUTPUT"
|
||||
echo "mulga: using branch ${BRANCH}"
|
||||
else
|
||||
echo "ref=main" >> "$GITHUB_OUTPUT"
|
||||
echo "mulga: branch ${BRANCH} not found, falling back to main"
|
||||
fi
|
||||
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
repository: mulgadc/mulga
|
||||
ref: ${{ steps.mulga-branch.outputs.ref }}
|
||||
token: ${{ steps.app-token.outputs.token }}
|
||||
sparse-checkout: scripts/tofu-cluster
|
||||
path: mulga
|
||||
|
||||
- name: Build install artifacts
|
||||
- name: Build Install Artifacts
|
||||
working-directory: mulga/scripts/tofu-cluster
|
||||
run: |
|
||||
./build-install-artifacts.sh "${GIT_BRANCH}" \
|
||||
@@ -95,7 +110,7 @@ jobs:
|
||||
|
||||
e2e_pseudo_multi:
|
||||
name: Pseudo Multi-Node E2E
|
||||
runs-on: [self-hosted, ci-pseudo]
|
||||
runs-on: [ self-hosted, ci-pseudo ]
|
||||
timeout-minutes: 30
|
||||
env:
|
||||
TOFU_LOG: /tmp/e2e-tofu-pseudo-${{ github.run_id }}.log
|
||||
@@ -110,16 +125,32 @@ jobs:
|
||||
private-key: ${{ secrets.APP_PRIVATE_KEY }}
|
||||
repositories: mulga
|
||||
|
||||
- name: Resolve Mulga Branch
|
||||
id: mulga-branch
|
||||
env:
|
||||
GH_TOKEN: ${{ steps.app-token.outputs.token }}
|
||||
BRANCH: ${{ github.ref_name }}
|
||||
run: |
|
||||
if gh api "repos/mulgadc/mulga/branches/${BRANCH}" >/dev/null 2>&1; then
|
||||
echo "ref=${BRANCH}" >> "$GITHUB_OUTPUT"
|
||||
echo "mulga: using branch ${BRANCH}"
|
||||
else
|
||||
echo "ref=main" >> "$GITHUB_OUTPUT"
|
||||
echo "mulga: branch ${BRANCH} not found, falling back to main"
|
||||
fi
|
||||
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
repository: mulgadc/mulga
|
||||
ref: ${{ steps.mulga-branch.outputs.ref }}
|
||||
token: ${{ steps.app-token.outputs.token }}
|
||||
sparse-checkout: scripts/tofu-cluster
|
||||
path: mulga
|
||||
|
||||
- name: Clone and build
|
||||
- name: Clone and Build
|
||||
working-directory: mulga/scripts/tofu-cluster
|
||||
run: ./build-artifacts.sh "${GIT_BRANCH}" "${RUNNER_TEMP}/spinifex-artifacts.tar"
|
||||
run: ./build-artifacts.sh "${GIT_BRANCH}"
|
||||
"${RUNNER_TEMP}/spinifex-artifacts.tar"
|
||||
|
||||
- name: Provision VM
|
||||
working-directory: mulga/scripts/tofu-cluster
|
||||
@@ -158,7 +189,7 @@ jobs:
|
||||
|
||||
e2e_real_multi:
|
||||
name: Real Multi-Node E2E
|
||||
runs-on: [self-hosted, ci-multi]
|
||||
runs-on: [ self-hosted, ci-multi ]
|
||||
timeout-minutes: 35
|
||||
env:
|
||||
TOFU_LOG: /tmp/e2e-tofu-multi-${{ github.run_id }}.log
|
||||
@@ -173,9 +204,24 @@ jobs:
|
||||
private-key: ${{ secrets.APP_PRIVATE_KEY }}
|
||||
repositories: mulga
|
||||
|
||||
- name: Resolve Mulga Branch
|
||||
id: mulga-branch
|
||||
env:
|
||||
GH_TOKEN: ${{ steps.app-token.outputs.token }}
|
||||
BRANCH: ${{ github.ref_name }}
|
||||
run: |
|
||||
if gh api "repos/mulgadc/mulga/branches/${BRANCH}" >/dev/null 2>&1; then
|
||||
echo "ref=${BRANCH}" >> "$GITHUB_OUTPUT"
|
||||
echo "mulga: using branch ${BRANCH}"
|
||||
else
|
||||
echo "ref=main" >> "$GITHUB_OUTPUT"
|
||||
echo "mulga: branch ${BRANCH} not found, falling back to main"
|
||||
fi
|
||||
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
repository: mulgadc/mulga
|
||||
ref: ${{ steps.mulga-branch.outputs.ref }}
|
||||
token: ${{ steps.app-token.outputs.token }}
|
||||
sparse-checkout: scripts/tofu-cluster
|
||||
path: mulga
|
||||
@@ -238,11 +284,11 @@ jobs:
|
||||
e2e_status:
|
||||
name: Report E2E Status
|
||||
if: always() && inputs.sha
|
||||
needs: [e2e_single, e2e_pseudo_multi, e2e_real_multi]
|
||||
runs-on: [self-hosted, ci-single]
|
||||
needs: [ e2e_single, e2e_pseudo_multi, e2e_real_multi ]
|
||||
runs-on: [ self-hosted, ci-single ]
|
||||
timeout-minutes: 5
|
||||
steps:
|
||||
- name: Report status to PR
|
||||
- name: Report Status to PR
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
run: |
|
||||
|
||||
@@ -2,7 +2,7 @@ name: Release
|
||||
|
||||
on:
|
||||
push:
|
||||
tags: ["v*"]
|
||||
tags: [ "v*" ]
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
@@ -82,7 +82,7 @@ jobs:
|
||||
spinifex/dist/spinifex-${{ github.ref_name }}-linux-arm64.tar.gz.sha256
|
||||
|
||||
release:
|
||||
needs: [distro-amd64, distro-arm64]
|
||||
needs: [ distro-amd64, distro-arm64 ]
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- name: Download amd64 Artifacts
|
||||
@@ -115,7 +115,7 @@ jobs:
|
||||
|
||||
verify:
|
||||
needs: release
|
||||
runs-on: [self-hosted, ci-single]
|
||||
runs-on: [ self-hosted, ci-single ]
|
||||
timeout-minutes: 25
|
||||
env:
|
||||
TOFU_LOG: /tmp/release-verify-${{ github.run_id }}.log
|
||||
@@ -132,9 +132,24 @@ jobs:
|
||||
private-key: ${{ secrets.APP_PRIVATE_KEY }}
|
||||
repositories: mulga
|
||||
|
||||
- name: Resolve Mulga Branch
|
||||
id: mulga-branch
|
||||
env:
|
||||
GH_TOKEN: ${{ steps.app-token.outputs.token }}
|
||||
BRANCH: ${{ github.ref_name }}
|
||||
run: |
|
||||
if gh api "repos/mulgadc/mulga/branches/${BRANCH}" >/dev/null 2>&1; then
|
||||
echo "ref=${BRANCH}" >> "$GITHUB_OUTPUT"
|
||||
echo "mulga: using branch ${BRANCH}"
|
||||
else
|
||||
echo "ref=main" >> "$GITHUB_OUTPUT"
|
||||
echo "mulga: branch ${BRANCH} not found, falling back to main"
|
||||
fi
|
||||
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
repository: mulgadc/mulga
|
||||
ref: ${{ steps.mulga-branch.outputs.ref }}
|
||||
token: ${{ steps.app-token.outputs.token }}
|
||||
sparse-checkout: scripts/tofu-cluster
|
||||
path: mulga
|
||||
|
||||
@@ -3,10 +3,9 @@
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://go.dev"><img src="https://img.shields.io/badge/Go-1.22+-00ADD8?style=flat-square&logo=go&logoColor=white" alt="Go"></a>
|
||||
<a href="https://go.dev"><img src="https://img.shields.io/badge/Go-1.26+-00ADD8?style=flat-square&logo=go&logoColor=white" alt="Go"></a>
|
||||
<a href="LICENSE"><img src="https://img.shields.io/badge/License-AGPL--3.0-3fb950?style=flat-square" alt="License"></a>
|
||||
<a href="https://docs.mulgadc.com"><img src="https://img.shields.io/badge/Docs-mulgadc.com-DC2626?style=flat-square" alt="Docs"></a>
|
||||
<a href="https://github.com/mulgadc/spinifex/actions"><img src="https://img.shields.io/badge/CI-e2e-58a6ff?style=flat-square" alt="CI"></a>
|
||||
<a href="https://docs.mulgadc.com"><img src="https://img.shields.io/badge/Docs-docs.mulgadc.com-DC2626?style=flat-square" alt="Docs"></a>
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
|
||||
@@ -1192,7 +1192,7 @@ func runAdminInitMultiNode(cmd *cobra.Command, accessKey, secretKey, accountID,
|
||||
fmt.Printf(" Waiting for %d more node(s) to join...\n", expectedNodes-1)
|
||||
fmt.Printf(" Token expires in %s\n\n", tokenTTL)
|
||||
fmt.Printf(" Other nodes should run:\n")
|
||||
fmt.Printf(" spx admin join --host %s --token %s --node <name> --bind <ip>\n\n", formationAddr, joinToken)
|
||||
fmt.Printf(" sudo spx admin join --host %s --token %s --node <name> --bind <ip>\n\n", formationAddr, joinToken)
|
||||
|
||||
// Wait for all nodes to register
|
||||
if err := fs.WaitForCompletion(formationTimeout); err != nil {
|
||||
|
||||
@@ -35,13 +35,25 @@ All services in the Spinifex platform are managed through this single binary.
|
||||
|
||||
## Account Management
|
||||
|
||||
Create a new isolated account with an admin user and AdministratorAccess policy:
|
||||
|
||||
```bash
|
||||
spx admin account create --name myteam
|
||||
export AWS_PROFILE=spinifex-myteam
|
||||
```
|
||||
|
||||
List all accounts:
|
||||
|
||||
```bash
|
||||
spx admin account list
|
||||
```
|
||||
|
||||
|
||||
|
||||
## Node Management
|
||||
|
||||
List nodes in the cluster:
|
||||
|
||||
```bash
|
||||
spx get nodes
|
||||
```
|
||||
@@ -59,6 +71,8 @@ node3 Ready 127.0.0.3 ap-southeast-2 ap-southeast-2a 2m 0
|
||||
spx top nodes
|
||||
```
|
||||
|
||||
Prints per-node CPU/memory usage and cluster-wide instance type availability.
|
||||
|
||||
## Image Management
|
||||
|
||||
```bash
|
||||
@@ -66,8 +80,13 @@ spx admin images list
|
||||
spx admin images import --name debian-12-arm64
|
||||
```
|
||||
|
||||
Catalog imports verify the image against the catalog-declared SHA-256/SHA-512 digest before extraction. Use `--file` to import operator-supplied media (verification skipped — operator is responsible for integrity), or `--force` to re-download after a checksum mismatch.
|
||||
|
||||
|
||||
## Cluster Shutdown
|
||||
|
||||
Coordinated, phased shutdown of the entire cluster (API/UI → VMs → viperblock → predastore → NATS/daemon):
|
||||
|
||||
```bash
|
||||
spx admin cluster shutdown
|
||||
```
|
||||
@@ -86,11 +105,12 @@ If you get permission errors during operations, ensure you're running with appro
|
||||
|
||||
### Services Fail to Start
|
||||
|
||||
Check the daemon logs for specific errors:
|
||||
Check the daemon logs for specific errors via `systemctl`/`journalctl`:
|
||||
|
||||
```bash
|
||||
ls ~/spinifex/logs/
|
||||
cat ~/spinifex/logs/spinifex.log
|
||||
systemctl status 'spinifex-*'
|
||||
journalctl -u spinifex-daemon -f
|
||||
journalctl -u 'spinifex-*' -f
|
||||
```
|
||||
|
||||
Common causes include port conflicts, missing OVN configuration, or untrusted CA certificates.
|
||||
|
||||
@@ -149,7 +149,7 @@ For production SSH via public IPs, see [Setting Up Your Cluster](/docs/setting-u
|
||||
Check QEMU logs for the instance and verify the AMI architecture matches your host:
|
||||
|
||||
```bash
|
||||
cat ~/spinifex/logs/spinifex.log
|
||||
journalctl -u spinifex-daemon -f
|
||||
aws ec2 describe-images --image-ids $SPINIFEX_AMI
|
||||
```
|
||||
|
||||
|
||||
@@ -1014,13 +1014,13 @@ sudo tcpdump -i {nic} -n "host {public_ip}"
|
||||
|
||||
```bash
|
||||
# vpcd log (reconcile, NAT, topology operations)
|
||||
cat ~/spinifex/logs/vpcd.log
|
||||
journalctl -u spinifex-vpcd -f
|
||||
|
||||
# ovn-controller log (port binding, commit failures)
|
||||
sudo cat /var/log/ovn/ovn-controller.log | tail -50
|
||||
|
||||
# Daemon log (instance launch, network setup)
|
||||
cat ~/spinifex/logs/spinifex.log
|
||||
journalctl -u spinifex-daemon -f
|
||||
```
|
||||
|
||||
### VPC Creation Fails
|
||||
@@ -1029,7 +1029,7 @@ Check OVN services and vpcd daemon:
|
||||
|
||||
```bash
|
||||
sudo systemctl is-active ovn-controller
|
||||
cat ~/spinifex/logs/vpcd.log
|
||||
journalctl -u spinifex-vpcd -f
|
||||
```
|
||||
|
||||
### Instances Cannot Reach Each Other
|
||||
@@ -1218,7 +1218,7 @@ sudo ovs-vsctl get Open_vSwitch . external-ids:system-id
|
||||
# What SB registered
|
||||
sudo ovn-sbctl list Chassis | grep name
|
||||
# What vpcd expects
|
||||
grep node ~/spinifex/config/spinifex.toml | head -1
|
||||
grep node /etc/spinifex/spinifex.toml | head -1
|
||||
```
|
||||
|
||||
**Fix:** `reset-dev-env.sh` passes `--chassis-id=chassis-node1` to
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
title: "Air-Gapped Install"
|
||||
description: "Deploy Spinifex in environments without internet connectivity. Covers offline package caching, USB deployment, and package verification."
|
||||
description: "Deploy Spinifex in environments without internet connectivity. Covers using a pre-built release tarball, mirrored APT packages, and locally-staged cloud images."
|
||||
category: "Getting Started"
|
||||
tags:
|
||||
- install
|
||||
@@ -9,8 +9,8 @@ tags:
|
||||
resources:
|
||||
- title: "Spinifex Repository"
|
||||
url: "https://github.com/mulgadc/spinifex"
|
||||
- title: "apt-cacher-ng"
|
||||
url: "https://wiki.debian.org/AptCacherNg"
|
||||
- title: "External Connection Inventory"
|
||||
url: "/docs/security/network-connections"
|
||||
---
|
||||
|
||||
# Air-Gapped Installation
|
||||
@@ -29,103 +29,158 @@ resources:
|
||||
|
||||
In air-gapped or disconnected environments, Spinifex can be deployed without internet access. This guide covers preparing offline packages on a connected machine, creating USB deployment media, and installing on the target server with package verification.
|
||||
|
||||
**Deployment methods:**
|
||||
- **apt-cacher-ng** — Local APT cache for Debian/Ubuntu packages
|
||||
- **Go module cache** — Pre-downloaded Go dependencies
|
||||
- **USB deployment** — Portable installation media with all dependencies
|
||||
- **GPG verification** — Cryptographic package integrity checks
|
||||
|
||||
## Instructions
|
||||
|
||||
## Step 1. Prepare Packages (on a connected machine)
|
||||
## Step 1. Download the Release (on a connected machine)
|
||||
|
||||
Set up a local APT cache to collect all required packages:
|
||||
Each Spinifex release publishes a self-contained tarball, the matching `setup.sh`, and a SHA-256 checksum to GitHub Releases. Resolve the latest tag and download the assets for your architecture:
|
||||
|
||||
```bash
|
||||
sudo apt install apt-cacher-ng
|
||||
sudo systemctl enable --now apt-cacher-ng
|
||||
ARCH=amd64 # or arm64
|
||||
TAG=$(curl -fsSL https://api.github.com/repos/mulgadc/spinifex/releases/latest \
|
||||
| grep '"tag_name"' | cut -d'"' -f4)
|
||||
|
||||
BASE="https://github.com/mulgadc/spinifex/releases/download/${TAG}"
|
||||
curl -fsSLO "${BASE}/spinifex-${TAG}-linux-${ARCH}.tar.gz"
|
||||
curl -fsSLO "${BASE}/spinifex-${TAG}-linux-${ARCH}.tar.gz.sha256"
|
||||
curl -fsSLO "${BASE}/setup.sh"
|
||||
|
||||
sha256sum -c "spinifex-${TAG}-linux-${ARCH}.tar.gz.sha256"
|
||||
```
|
||||
|
||||
Pre-download all Spinifex dependencies:
|
||||
## Step 2. Stage Dependencies (on the connected machine)
|
||||
|
||||
Pre-download the APT packages installed by the production setup. `apt install --download-only` writes `.deb` files to `/var/cache/apt/archives/` without installing them, so the connected machine isn't modified:
|
||||
|
||||
```bash
|
||||
sudo apt install --download-only nbdkit nbdkit-plugin-dev pkg-config \
|
||||
qemu-system qemu-utils qemu-kvm libvirt-daemon-system \
|
||||
libvirt-clients libvirt-dev make gcc unzip xz-utils file \
|
||||
ovn-central ovn-host openvswitch-switch
|
||||
sudo apt update
|
||||
sudo apt install --download-only -y \
|
||||
nbdkit nbdkit-plugin-dev pkg-config \
|
||||
qemu-system-x86 qemu-utils qemu-kvm \
|
||||
libvirt-daemon-system libvirt-clients libvirt-dev \
|
||||
ovn-central ovn-host openvswitch-switch \
|
||||
dhcpcd-base make gcc jq curl iproute2 netcat-openbsd \
|
||||
wget unzip xz-utils file
|
||||
```
|
||||
|
||||
## Step 2. Create USB Deployment Media
|
||||
Download AWS CLI v2:
|
||||
|
||||
```bash
|
||||
mkdir -p /media/spinifex-deploy/{apt-packages,go-cache,spinifex-source}
|
||||
curl -fsSL "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" \
|
||||
-o awscliv2.zip
|
||||
```
|
||||
|
||||
Mirror the cloud image you intend to run as guest VMs:
|
||||
|
||||
```bash
|
||||
mkdir -p images
|
||||
curl -fsSL "https://cdimage.debian.org/cdimage/cloud/bookworm/latest/debian-12-genericcloud-amd64.qcow2" \
|
||||
-o images/debian-12-amd64.qcow2
|
||||
```
|
||||
|
||||
## Step 3. Assemble Transfer Media
|
||||
|
||||
```bash
|
||||
mkdir -p /media/spinifex-deploy/{tarball,apt-packages,aws,images}
|
||||
cp spinifex-${TAG}-linux-${ARCH}.tar.gz /media/spinifex-deploy/tarball/
|
||||
cp setup.sh /media/spinifex-deploy/
|
||||
cp /var/cache/apt/archives/*.deb /media/spinifex-deploy/apt-packages/
|
||||
cp -r ~/go/pkg/mod/cache/ /media/spinifex-deploy/go-cache/
|
||||
cp -r ~/Development/mulga/spinifex /media/spinifex-deploy/spinifex-source/
|
||||
cp awscliv2.zip /media/spinifex-deploy/aws/
|
||||
cp images/*.qcow2 /media/spinifex-deploy/images/
|
||||
```
|
||||
|
||||
## Step 3. Verify Package Integrity
|
||||
## Step 4. Install on the Air-Gapped Target
|
||||
|
||||
Sign and verify packages before transferring to the target:
|
||||
|
||||
```bash
|
||||
gpg --import /media/spinifex-deploy/mulga-signing-key.asc
|
||||
gpg --verify spinifex-v1.0.tar.gz.sig spinifex-v1.0.tar.gz
|
||||
sha256sum -c /media/spinifex-deploy/checksums.sha256
|
||||
```
|
||||
|
||||
## Step 4. Install on the Target Server
|
||||
|
||||
Mount the USB and install:
|
||||
Mount the media, install APT dependencies, install AWS CLI, then run `setup.sh` with the local tarball:
|
||||
|
||||
```bash
|
||||
sudo mount /dev/sdb1 /mnt/usb
|
||||
|
||||
sudo dpkg -i /mnt/usb/apt-packages/*.deb
|
||||
cp -r /mnt/usb/spinifex-source ~/Development/mulga/spinifex
|
||||
cd ~/Development/mulga/spinifex && make build
|
||||
sudo apt-get install -f --no-download # resolve any leftover deps from local cache
|
||||
|
||||
cd /tmp && unzip /mnt/usb/aws/awscliv2.zip && sudo ./aws/install
|
||||
|
||||
INSTALL_SPINIFEX_TARBALL=/mnt/usb/tarball/spinifex-*-linux-*.tar.gz \
|
||||
INSTALL_SPINIFEX_SKIP_APT=1 \
|
||||
INSTALL_SPINIFEX_SKIP_AWS=1 \
|
||||
bash /mnt/usb/setup.sh
|
||||
```
|
||||
|
||||
Then follow the [Source Install](/docs/install-source) guide from Step 3 (Setup OVN) onwards.
|
||||
Run `setup.sh` without `sudo` — the script handles privilege escalation internally and ends by `exec`-ing into a `newgrp spinifex` subshell so your current shell picks up `spinifex` group membership. Without that membership, AWS CLI cannot traverse `/etc/spinifex/` (mode `0750`) to read `ca.pem` and Step 9 will fail with a TLS error. Type `exit` to leave the subshell when finished.
|
||||
|
||||
## Step 5. Setup OVN Networking
|
||||
|
||||
`spx admin init` requires OVN/OVS to be configured before the daemon can manage tenant networks. `setup-ovn.sh` ships in the tarball and runs purely against local commands (no network access required):
|
||||
|
||||
```bash
|
||||
sudo /usr/local/share/spinifex/setup-ovn.sh --management
|
||||
```
|
||||
|
||||
If your WAN interface is a physical NIC rather than a bridge, pass `--wan-bridge=br-wan --wan-iface=<nic>`.
|
||||
|
||||
## Step 6. Initialize Without Telemetry
|
||||
|
||||
```bash
|
||||
sudo spx admin init --node node1 --nodes 1 --no-telemetry
|
||||
```
|
||||
|
||||
This generates the cluster configuration, TLS certificates, installs the CA into the system trust store, and writes AWS CLI credentials. See [Single-Node Install](/docs/install) for what `spx admin init` does.
|
||||
|
||||
## Step 7. Start Services
|
||||
|
||||
`setup.sh` enables `spinifex.target` but does not start it on a fresh install. Start it now so predastore is online before you import images:
|
||||
|
||||
```bash
|
||||
sudo systemctl start spinifex.target
|
||||
```
|
||||
|
||||
## Step 8. Import Cloud Images
|
||||
|
||||
Register the pre-staged image with Spinifex:
|
||||
|
||||
```bash
|
||||
sudo spx admin images import --file /mnt/usb/images/debian-12-amd64.qcow2 \
|
||||
--distro debian --version 12 --arch x86_64
|
||||
```
|
||||
|
||||
## Step 9. Verify
|
||||
|
||||
```bash
|
||||
export AWS_PROFILE=spinifex
|
||||
aws ec2 describe-instance-types
|
||||
aws ec2 describe-images
|
||||
```
|
||||
|
||||
If both calls return data, your air-gapped install is working. Continue to [Setting Up Your Cluster](/docs/setting-up-your-cluster) to launch your first instance.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Missing Dependencies After dpkg Install
|
||||
### Missing APT Dependencies
|
||||
|
||||
Some packages may have unresolved dependencies. Fix with:
|
||||
`dpkg -i` does not resolve transitive dependencies. After installing, run:
|
||||
|
||||
```bash
|
||||
sudo dpkg -i /mnt/usb/apt-packages/*.deb
|
||||
sudo apt-get install -f
|
||||
sudo apt-get install -f --no-download
|
||||
```
|
||||
|
||||
The `-f` flag tells apt to fix broken dependencies using what's available locally.
|
||||
The `--no-download` flag forces apt to use only what's in the local cache. If a dependency is genuinely missing, add it to the `apt --download-only` step on the connected machine and re-stage.
|
||||
|
||||
### GPG Verification Fails
|
||||
### Setup.sh Tries to Download Anyway
|
||||
|
||||
The signing key may not match or the download was corrupted. Re-import the key and verify:
|
||||
Confirm both skip flags are exported and that `INSTALL_SPINIFEX_TARBALL` points at a readable file:
|
||||
|
||||
```bash
|
||||
gpg --import /media/spinifex-deploy/mulga-signing-key.asc
|
||||
gpg --verify spinifex-v1.0.tar.gz.sig spinifex-v1.0.tar.gz
|
||||
sudo INSTALL_SPINIFEX_TARBALL=/mnt/usb/tarball/spinifex-...tar.gz \
|
||||
INSTALL_SPINIFEX_SKIP_APT=1 \
|
||||
INSTALL_SPINIFEX_SKIP_AWS=1 \
|
||||
bash -x /mnt/usb/setup.sh
|
||||
```
|
||||
|
||||
If verification still fails, re-download the package on the connected machine and compare checksums:
|
||||
### Init Telemetry Attempted
|
||||
|
||||
```bash
|
||||
sha256sum spinifex-v1.0.tar.gz
|
||||
```
|
||||
`spx admin init` posts a one-shot record to `https://install.mulgadc.com/install`. Pass `--no-telemetry` on every `init` and `join` invocation, or export `SPX_NO_TELEMETRY=1` in the operator's shell profile.
|
||||
|
||||
### Go Module Cache Errors
|
||||
### Image Import Fails
|
||||
|
||||
The Go module cache may have been incompletely copied. On the connected machine, re-export the full cache:
|
||||
|
||||
```bash
|
||||
cp -r ~/go/pkg/mod/cache/ /media/spinifex-deploy/go-cache/
|
||||
```
|
||||
|
||||
On the target, restore it:
|
||||
|
||||
```bash
|
||||
mkdir -p ~/go/pkg/mod/
|
||||
cp -r /mnt/usb/go-cache ~/go/pkg/mod/cache
|
||||
```
|
||||
`spx admin images import --file` requires the distro/version/arch flags so the image registers in the catalogue. If the import succeeds but `aws ec2 describe-images` returns empty, check `journalctl -u spinifex-daemon -f` for predastore upload errors.
|
||||
|
||||
@@ -31,7 +31,7 @@ resources:
|
||||
|
||||
A Spinifex cluster distributes services across multiple servers for high availability, data durability, and fault tolerance. Cluster formation is automatic — the init node waits for peers to join, then distributes credentials, CA certificates, and configuration.
|
||||
|
||||
**Network requirements:**
|
||||
**Network Requirements:**
|
||||
|
||||
- Minimum 1 NIC per server (2 recommended for production)
|
||||
- UDP port 6081 open between hosts (Geneve tunnels)
|
||||
@@ -59,7 +59,7 @@ export AWS_AZ=us-east-1a
|
||||
|
||||
## Step 3. Setup OVN Networking
|
||||
|
||||
Server 1 runs OVN central and must be set up first. If your WAN interface is already a bridge (e.g. `br-wan`), setup-ovn.sh auto-detects it. Otherwise use `--wan-bridge=br-wan --wan-iface=eth1` (dedicated WAN NIC).
|
||||
Server 1 runs OVN central and must be set up first. If your WAN interface is already a bridge, setup-ovn.sh auto-detects it. Otherwise use `--wan-bridge=br-wan --wan-iface=eth1` (dedicated WAN NIC).
|
||||
|
||||
**Server 1:**
|
||||
|
||||
@@ -104,8 +104,6 @@ sudo spx admin init \
|
||||
--port 4432 --region $AWS_REGION --az $AWS_AZ
|
||||
```
|
||||
|
||||
Save the admin credentials — they will not be shown again.
|
||||
|
||||
The init output displays the join command including the token:
|
||||
|
||||
```
|
||||
@@ -114,7 +112,7 @@ The init output displays the join command including the token:
|
||||
Token expires in 30m0s
|
||||
|
||||
Other nodes should run:
|
||||
spx admin join --host 10.0.0.1:4432 --token spx_join_a8Bf3x9Kz2mN --node <name> --bind <ip>
|
||||
sudo spx admin join --host 10.0.0.1:4432 --token spx_join_a8Bf3x9Kz2mN --node <name> --bind <ip>
|
||||
```
|
||||
|
||||
**Server 2 — Join** (while init is running):
|
||||
@@ -135,8 +133,7 @@ sudo spx admin join \
|
||||
--region $AWS_REGION --az $AWS_AZ
|
||||
```
|
||||
|
||||
> **Note:** The join token expires 30 minutes after init by default. For larger deployments
|
||||
> with slower provisioning, use `--token-ttl 2h` on the init command.
|
||||
**Note:** The join token expires 30 minutes after init by default. For larger deployments with slower provisioning, use `--token-ttl 2h`
|
||||
|
||||
## Step 5. Start Services
|
||||
|
||||
@@ -181,7 +178,7 @@ sudo ss -tlnp | grep 6642
|
||||
### CA Certificate Not Trusted
|
||||
|
||||
```bash
|
||||
sudo cp ~/spinifex/config/ca.pem /usr/local/share/ca-certificates/spinifex-ca.crt
|
||||
sudo cp /etc/spinifex/ca.pem /usr/local/share/ca-certificates/spinifex-ca.crt
|
||||
sudo update-ca-certificates
|
||||
```
|
||||
|
||||
|
||||
@@ -52,43 +52,17 @@ export PATH=$PATH:/usr/local/go/bin
|
||||
```bash
|
||||
cd spinifex
|
||||
./scripts/clone-deps.sh
|
||||
./scripts/dev-setup.sh
|
||||
```
|
||||
|
||||
Confirm `./bin/spx` exists.
|
||||
|
||||
## Step 3. Setup OVN
|
||||
|
||||
If your WAN interface is already a bridge (e.g. `br-wan`), setup-ovn.sh auto-detects it:
|
||||
|
||||
```bash
|
||||
./scripts/setup-ovn.sh --management
|
||||
```
|
||||
|
||||
If your WAN is a physical NIC:
|
||||
|
||||
```bash
|
||||
# Dedicated WAN NIC (not your SSH connection):
|
||||
./scripts/setup-ovn.sh --management --wan-bridge=br-wan --wan-iface=eth1
|
||||
```
|
||||
|
||||
## Step 4. Development initialisation
|
||||
## Step 3. Development Initialisation
|
||||
|
||||
```bash
|
||||
./scripts/dev-install.sh
|
||||
```
|
||||
|
||||
Note, this will bootstrap a single node development environment
|
||||
This bootstraps a single-node development environment: builds binaries, configures OVN, initialises the cluster, installs the CA certificate, and starts all services.
|
||||
|
||||
## Step 5. Start services
|
||||
|
||||
```bash
|
||||
sudo systemctl status spinifex.target
|
||||
```
|
||||
|
||||
Start all services
|
||||
|
||||
## Step 6. Verify Installation
|
||||
## Step 4. Verify Installation
|
||||
|
||||
```bash
|
||||
export AWS_PROFILE=spinifex
|
||||
@@ -109,15 +83,9 @@ Continue to [Setting Up Your Cluster](/docs/setting-up-your-cluster) to import a
|
||||
export PATH=$PATH:/usr/local/go/bin
|
||||
```
|
||||
|
||||
### ./bin/spx Missing After Build
|
||||
|
||||
```bash
|
||||
./scripts/dev-setup.sh
|
||||
```
|
||||
|
||||
### CA Certificate Not Trusted
|
||||
|
||||
```bash
|
||||
sudo cp ~/spinifex/config/ca.pem /usr/local/share/ca-certificates/spinifex-ca.crt
|
||||
sudo cp /etc/spinifex/ca.pem /usr/local/share/ca-certificates/spinifex-ca.crt
|
||||
sudo update-ca-certificates
|
||||
```
|
||||
|
||||
@@ -29,7 +29,7 @@ resources:
|
||||
|
||||
## Overview
|
||||
|
||||
Spinifex is an open-source infrastructure platform that brings core AWS services — EC2, VPC, EBS, and S3 — to bare-metal, edge, and on-prem environments.
|
||||
Spinifex is an open-source infrastructure platform that brings core AWS services to bare-metal, edge, and on-prem environments.
|
||||
|
||||
This guide installs Spinifex on a single server using the binary installer. For multi-server clusters, see [Multi-Node Install](/docs/install-multi-node). To build from source, see [Source Install](/docs/install-source).
|
||||
|
||||
@@ -65,10 +65,9 @@ If your WAN interface is already a bridge (e.g. `br-wan`), setup-ovn.sh auto-det
|
||||
sudo /usr/local/share/spinifex/setup-ovn.sh --management
|
||||
```
|
||||
|
||||
If your WAN is a physical NIC, choose one:
|
||||
If your WAN is a physical NIC:
|
||||
|
||||
```bash
|
||||
# Dedicated WAN NIC (not your SSH connection):
|
||||
sudo /usr/local/share/spinifex/setup-ovn.sh --management --wan-bridge=br-wan --wan-iface=eth1
|
||||
```
|
||||
|
||||
@@ -86,7 +85,7 @@ This is recommended for production and required in multi-node deployments. See [
|
||||
sudo spx admin init --node node1 --nodes 1
|
||||
```
|
||||
|
||||
This auto-detects your network topology, generates configuration and TLS certificates, installs the CA into the system trust store, and configures AWS CLI credentials. Save the admin credentials printed during init — they will not be shown again.
|
||||
This auto-detects your network topology, generates configuration and TLS certificates, installs the CA into the system trust store, and configures AWS CLI credentials (saved in `~/.aws/credentials`)
|
||||
|
||||
## Step 4. Start Services
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@ resources:
|
||||
## Overview
|
||||
|
||||
This guide assumes Spinifex is already installed and running. If not, follow one of the installation guides first:
|
||||
- [Binary Install (Single Node)](/docs/install)
|
||||
- [Single-Node Install)](/docs/install)
|
||||
- [Multi-Node Install](/docs/install-multi-node)
|
||||
- [Source Install](/docs/install-source)
|
||||
|
||||
@@ -57,11 +57,12 @@ spx admin images list
|
||||
```
|
||||
|
||||
```
|
||||
NAME | DISTRO | VERSION | ARCH | BOOT
|
||||
debian-12-arm64 | debian | 12 | arm64 | bios
|
||||
debian-12-x86_64 | debian | 12 | x86_64 | bios
|
||||
ubuntu-24.04-arm64 | ubuntu | 24.04 | arm64 | bios
|
||||
ubuntu-24.04-x86_64 | ubuntu | 24.04 | x86_64 | bios
|
||||
NAME | DISTRO | VERSION | ARCH | BOOT
|
||||
debian-12-arm64 | debian | 12 | arm64 | bios
|
||||
debian-12-x86_64 | debian | 12 | x86_64 | bios
|
||||
lb-alpine-3.21.6-x86_64 | alpine | 3.21.6 | x86_64 | bios
|
||||
ubuntu-24.04-arm64 | ubuntu | 24.04 | arm64 | bios
|
||||
ubuntu-24.04-x86_64 | ubuntu | 24.04 | x86_64 | bios
|
||||
```
|
||||
|
||||
Import an image:
|
||||
@@ -344,7 +345,7 @@ export AWS_PROFILE=spinifex-myteam
|
||||
### Instance Stuck in Pending
|
||||
|
||||
```bash
|
||||
cat ~/spinifex/logs/spinifex.log
|
||||
journalctl -u spinifex-daemon -f
|
||||
aws ec2 describe-images
|
||||
```
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
---
|
||||
title: "Updating Spinifex"
|
||||
description: "Upgrade an existing Spinifex installation to the latest release."
|
||||
category: "Getting Started"
|
||||
category: "Administration"
|
||||
tags:
|
||||
- update
|
||||
- upgrade
|
||||
@@ -10,7 +10,7 @@ resources:
|
||||
- title: "Spinifex Repository"
|
||||
url: "https://github.com/mulgadc/spinifex"
|
||||
- title: "Single-Node Install"
|
||||
url: "https://docs.mulgadc.com/docs/install"
|
||||
url: "/docs/install"
|
||||
---
|
||||
|
||||
# Updating Spinifex
|
||||
|
||||
@@ -129,7 +129,7 @@ Operators own remediation for layers Spinifex does not ship:
|
||||
| Host OS + kernel | Track distribution advisories (Debian DSA, Ubuntu USN) at matching cadence. |
|
||||
| OVN / OVS | Patched via the operator's package channel alongside the OS. |
|
||||
| QEMU / KVM / libvirt | As above — hypervisor CVEs affect tenant isolation. |
|
||||
| Host AV / EDR agent | See https://docs.mulgadc.com/docs/security/malware-protection §2. |
|
||||
| Host AV / EDR agent | See [Malware Protection §2](/docs/security/malware-protection#2-update-requirements-sil1-3144). |
|
||||
|
||||
Operators should subscribe to the `mulgadc/spinifex` release feed (Watch → Custom → Releases + Security Advisories) so Critical/High advisories arrive via GitHub's notification channel rather than polling.
|
||||
|
||||
|
||||
@@ -114,7 +114,7 @@ Spinifex nodes initiate a small, fixed set of outbound connections.
|
||||
|
||||
**Update checks and metadata.** Spinifex does not check for updates and does not consume a cloud metadata service (`169.254.169.254` is served *by* the cluster to guest VMs). Node software updates come from the operator's OS package channel. The install-telemetry endpoint above is the only vendor-operated destination contacted by a node; closed-egress deployments should disable it and record the opt-out in the security plan.
|
||||
|
||||
**Air-gapped deployments.** The three image URLs are the only destinations needed for the standard image catalogue. Mirror them locally and use `spx admin images import --file` with pre-staged files. Telemetry must also be disabled. See [Air-gapped install](https://docs.mulgadc.com/docs/install-airgapped).
|
||||
**Air-gapped deployments.** The three image URLs are the only destinations needed for the standard image catalogue. Mirror them locally and use `spx admin images import --file` with pre-staged files. Telemetry must also be disabled. See [Air-Gapped Install](/docs/install-airgapped).
|
||||
|
||||
## 3. Cross-Node (Internal) Connections
|
||||
|
||||
|
||||
@@ -144,7 +144,7 @@ Every entry into a protected space must produce a log entry capturing:
|
||||
|
||||
### 4.3 Integration with Spinifex Logs
|
||||
|
||||
Forward physical-access events to the same SIEM or log collector used for Spinifex service logs (see [Malware Protection §3](https://docs.mulgadc.com/docs/security/malware-protection#3-scan-schedule-sil1-3145)) so a `master.key` access attempt can be correlated with a physical entry into the rack.
|
||||
Forward physical-access events to the same SIEM or log collector used for Spinifex service logs (see [Malware Protection §3](/docs/security/malware-protection#3-scan-schedule-sil1-3145)) so a `master.key` access attempt can be correlated with a physical entry into the rack.
|
||||
|
||||
## 5. Manage Physical Access Devices (PE.L1-3.10.5)
|
||||
|
||||
@@ -199,7 +199,7 @@ Use this list to confirm a site meets the four CMMC practices before admitting S
|
||||
- CCTV or equivalent monitoring covers the rack fronts, rears, and console positions, with 30-day minimum retention.
|
||||
- Physical access logs are produced for every entry, retained 12 months, and reviewed on the cadence in [§4.2](#42-retention-and-review).
|
||||
- Door-forced, door-held, and out-of-hours events alert the on-call operator.
|
||||
- Physical access events forwarded to the SIEM used for Spinifex service logs (see [Malware Protection §3](https://docs.mulgadc.com/docs/security/malware-protection#3-scan-schedule-sil1-3145)).
|
||||
- Physical access events forwarded to the SIEM used for Spinifex service logs (see [Malware Protection §3](/docs/security/malware-protection#3-scan-schedule-sil1-3145)).
|
||||
- Device register reconciles quarterly against the access-control system and physical key count; discrepancies are closed before sign-off.
|
||||
- Lost-device and termination procedures trigger immediate revocation per [§5.2](#52-control-b).
|
||||
- System security plan references this guide and records the facility, access-control product, CCTV retention, and log-forwarding destination.
|
||||
|
||||
@@ -58,7 +58,6 @@ Deploy a VPC with public and private subnets where the private subnet has no int
|
||||
- Spinifex installed and running (see [Installing Spinifex](/docs/install))
|
||||
- A Debian 12 AMI imported (see [Setting Up Your Cluster](/docs/setting-up-your-cluster))
|
||||
- OpenTofu or Terraform installed
|
||||
- `AWS_PROFILE=spinifex` configured
|
||||
|
||||
## Instructions
|
||||
|
||||
|
||||
@@ -68,7 +68,6 @@ Deploy two Nginx web servers behind an internet-facing Application Load Balancer
|
||||
- Spinifex installed and running (see [Installing Spinifex](/docs/install))
|
||||
- A Debian 12 AMI imported (see [Setting Up Your Cluster](/docs/setting-up-your-cluster))
|
||||
- OpenTofu or Terraform installed
|
||||
- `AWS_PROFILE=spinifex` configured
|
||||
|
||||
## Instructions
|
||||
|
||||
|
||||
@@ -1,14 +1,18 @@
|
||||
# Example: Nginx Web Servers with ALB on Spinifex
|
||||
#
|
||||
# Deploys a VPC with two public subnets (ALB + NAT Gateway) and two private
|
||||
# subnets hosting Nginx EC2 instances. An internet-facing Application Load
|
||||
# Balancer distributes HTTP traffic between the private workers, and the
|
||||
# NAT Gateway gives them outbound internet access so cloud-init can install
|
||||
# Nginx from the Debian apt repository.
|
||||
# Deploys a VPC with two public subnets hosting Nginx EC2 instances and an
|
||||
# internet-facing Application Load Balancer. Workers sit in public subnets
|
||||
# with auto-assigned public IPs purely so cloud-init can apt-install nginx.
|
||||
# The ALB targets them by primary private IP (target_type=instance), so
|
||||
# load-balanced traffic stays on the private VPC network.
|
||||
#
|
||||
# Demonstrates: VPC, public and private subnets, internet gateway, NAT
|
||||
# Gateway with Elastic IP, route tables, security group, key pair, cloud-init
|
||||
# user-data, EC2 instances, ALB, target group, and listener.
|
||||
# In a production deployment, workers would be in private subnets with
|
||||
# nginx baked into a custom AMI (or installed via a private repository
|
||||
# mirror), and a NAT Gateway would be unnecessary for this workload.
|
||||
#
|
||||
# Demonstrates: VPC, public subnets, internet gateway, route tables,
|
||||
# security group, key pair, cloud-init user-data, EC2 instances with
|
||||
# auto-assigned public IPs, ALB, target group, and listener.
|
||||
#
|
||||
# Usage:
|
||||
# cd spinifex/docs/terraform/nginx-alb
|
||||
@@ -152,9 +156,10 @@ resource "aws_internet_gateway" "igw" {
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
resource "aws_subnet" "public_a" {
|
||||
vpc_id = aws_vpc.main.id
|
||||
cidr_block = "10.20.1.0/24"
|
||||
availability_zone = data.aws_availability_zones.available.names[0]
|
||||
vpc_id = aws_vpc.main.id
|
||||
cidr_block = "10.20.1.0/24"
|
||||
availability_zone = data.aws_availability_zones.available.names[0]
|
||||
map_public_ip_on_launch = true
|
||||
|
||||
tags = {
|
||||
Name = "nginx-alb-public-a"
|
||||
@@ -162,9 +167,10 @@ resource "aws_subnet" "public_a" {
|
||||
}
|
||||
|
||||
resource "aws_subnet" "public_b" {
|
||||
vpc_id = aws_vpc.main.id
|
||||
cidr_block = "10.20.2.0/24"
|
||||
availability_zone = data.aws_availability_zones.available.names[0]
|
||||
vpc_id = aws_vpc.main.id
|
||||
cidr_block = "10.20.2.0/24"
|
||||
availability_zone = data.aws_availability_zones.available.names[0]
|
||||
map_public_ip_on_launch = true
|
||||
|
||||
tags = {
|
||||
Name = "nginx-alb-public-b"
|
||||
@@ -172,58 +178,7 @@ resource "aws_subnet" "public_b" {
|
||||
}
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Private Subnets (two AZs for the Nginx workers)
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
resource "aws_subnet" "private_a" {
|
||||
vpc_id = aws_vpc.main.id
|
||||
cidr_block = "10.20.11.0/24"
|
||||
availability_zone = data.aws_availability_zones.available.names[0]
|
||||
|
||||
tags = {
|
||||
Name = "nginx-alb-private-a"
|
||||
}
|
||||
}
|
||||
|
||||
resource "aws_subnet" "private_b" {
|
||||
vpc_id = aws_vpc.main.id
|
||||
cidr_block = "10.20.12.0/24"
|
||||
availability_zone = data.aws_availability_zones.available.names[0]
|
||||
|
||||
tags = {
|
||||
Name = "nginx-alb-private-b"
|
||||
}
|
||||
}
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# NAT Gateway — outbound internet for the private subnets
|
||||
#
|
||||
# Background plumbing: the private-subnet workers need outbound connectivity
|
||||
# during cloud-init so apt-get can install Nginx. A single NAT Gateway in
|
||||
# public_a provides SNAT for both private subnets via the private route table.
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
resource "aws_eip" "nat" {
|
||||
domain = "vpc"
|
||||
|
||||
tags = {
|
||||
Name = "nginx-alb-nat-eip"
|
||||
}
|
||||
}
|
||||
|
||||
resource "aws_nat_gateway" "main" {
|
||||
allocation_id = aws_eip.nat.id
|
||||
subnet_id = aws_subnet.public_a.id
|
||||
|
||||
tags = {
|
||||
Name = "nginx-alb-nat"
|
||||
}
|
||||
|
||||
depends_on = [aws_internet_gateway.igw]
|
||||
}
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Route Tables — public subnets egress via IGW, private subnets via NAT GW
|
||||
# Route Table — public subnets egress via IGW
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
resource "aws_route_table" "public" {
|
||||
@@ -249,29 +204,6 @@ resource "aws_route_table_association" "public_b" {
|
||||
route_table_id = aws_route_table.public.id
|
||||
}
|
||||
|
||||
resource "aws_route_table" "private" {
|
||||
vpc_id = aws_vpc.main.id
|
||||
|
||||
route {
|
||||
cidr_block = "0.0.0.0/0"
|
||||
nat_gateway_id = aws_nat_gateway.main.id
|
||||
}
|
||||
|
||||
tags = {
|
||||
Name = "nginx-alb-private-rt"
|
||||
}
|
||||
}
|
||||
|
||||
resource "aws_route_table_association" "private_a" {
|
||||
subnet_id = aws_subnet.private_a.id
|
||||
route_table_id = aws_route_table.private.id
|
||||
}
|
||||
|
||||
resource "aws_route_table_association" "private_b" {
|
||||
subnet_id = aws_subnet.private_b.id
|
||||
route_table_id = aws_route_table.private.id
|
||||
}
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Security Group — SSH + HTTP inbound, all outbound
|
||||
# ---------------------------------------------------------------------------
|
||||
@@ -318,14 +250,10 @@ resource "aws_instance" "nginx_1" {
|
||||
ami = data.aws_ami.debian12.id
|
||||
instance_type = var.instance_type
|
||||
|
||||
subnet_id = aws_subnet.private_a.id
|
||||
subnet_id = aws_subnet.public_a.id
|
||||
vpc_security_group_ids = [aws_security_group.web.id]
|
||||
key_name = aws_key_pair.nginx.key_name
|
||||
|
||||
# Workers pull nginx from apt via the NAT Gateway — creation must wait
|
||||
# until the NAT Gateway is available so cloud-init can reach the repos.
|
||||
depends_on = [aws_nat_gateway.main]
|
||||
|
||||
user_data_base64 = base64encode(<<-USERDATA
|
||||
#!/bin/bash
|
||||
set -euo pipefail
|
||||
@@ -362,14 +290,10 @@ resource "aws_instance" "nginx_2" {
|
||||
ami = data.aws_ami.debian12.id
|
||||
instance_type = var.instance_type
|
||||
|
||||
subnet_id = aws_subnet.private_b.id
|
||||
subnet_id = aws_subnet.public_b.id
|
||||
vpc_security_group_ids = [aws_security_group.web.id]
|
||||
key_name = aws_key_pair.nginx.key_name
|
||||
|
||||
# Workers pull nginx from apt via the NAT Gateway — creation must wait
|
||||
# until the NAT Gateway is available so cloud-init can reach the repos.
|
||||
depends_on = [aws_nat_gateway.main]
|
||||
|
||||
user_data_base64 = base64encode(<<-USERDATA
|
||||
#!/bin/bash
|
||||
set -euo pipefail
|
||||
|
||||
@@ -45,7 +45,6 @@ Deploy a complete Nginx web server on Spinifex using Terraform/OpenTofu. This wo
|
||||
- Spinifex installed and running (see [Installing Spinifex](/docs/install))
|
||||
- A Debian 12 AMI imported (see [Setting Up Your Cluster](/docs/setting-up-your-cluster))
|
||||
- OpenTofu or Terraform installed
|
||||
- `AWS_PROFILE=spinifex` configured
|
||||
|
||||
## Instructions
|
||||
|
||||
|
||||
@@ -55,7 +55,6 @@ Deploy an EC2 instance running a Flask file-sharing web application backed by S3
|
||||
- Predastore running (S3 API on port 8443)
|
||||
- A Debian 12 AMI imported (see [Setting Up Your Cluster](/docs/setting-up-your-cluster))
|
||||
- OpenTofu or Terraform installed
|
||||
- `AWS_PROFILE=spinifex` configured
|
||||
- The EC2 instance must be able to reach Predastore — use the host's br-wan IP, not localhost
|
||||
|
||||
## Instructions
|
||||
|
||||
@@ -13,8 +13,8 @@ require (
|
||||
github.com/klauspost/cpuid/v2 v2.3.0
|
||||
github.com/mulgadc/predastore v1.1.6
|
||||
github.com/mulgadc/viperblock v1.1.6
|
||||
github.com/nats-io/nats-server/v2 v2.12.6
|
||||
github.com/nats-io/nats.go v1.50.0
|
||||
github.com/nats-io/nats-server/v2 v2.12.7
|
||||
github.com/nats-io/nats.go v1.51.0
|
||||
github.com/ovn-kubernetes/libovsdb v0.8.1
|
||||
github.com/pelletier/go-toml/v2 v2.3.0
|
||||
github.com/pterm/pterm v0.12.83
|
||||
|
||||
@@ -301,10 +301,10 @@ github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRW
|
||||
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||
github.com/nats-io/jwt/v2 v2.8.1 h1:V0xpGuD/N8Mi+fQNDynXohVvp7ZztevW5io8CUWlPmU=
|
||||
github.com/nats-io/jwt/v2 v2.8.1/go.mod h1:nWnOEEiVMiKHQpnAy4eXlizVEtSfzacZ1Q43LIRavZg=
|
||||
github.com/nats-io/nats-server/v2 v2.12.6 h1:Egbx9Vl7Ch8wTtpXPGqbehkZ+IncKqShUxvrt1+Enc8=
|
||||
github.com/nats-io/nats-server/v2 v2.12.6/go.mod h1:4HPlrvtmSO3yd7KcElDNMx9kv5EBJBnJJzQPptXlheo=
|
||||
github.com/nats-io/nats.go v1.50.0 h1:5zAeQrTvyrKrWLJ0fu02W3br8ym57qf7csDzgLOpcds=
|
||||
github.com/nats-io/nats.go v1.50.0/go.mod h1:26HypzazeOkyO3/mqd1zZd53STJN0EjCYF9Uy2ZOBno=
|
||||
github.com/nats-io/nats-server/v2 v2.12.7 h1:prQ9cPiWHcnwfT81Wi5lU9LL8TLY+7pxDru6fQYLCQQ=
|
||||
github.com/nats-io/nats-server/v2 v2.12.7/go.mod h1:dOnmkprKMluTmTF7/QHZioxlau3sKHUM/LBPy9AiBPw=
|
||||
github.com/nats-io/nats.go v1.51.0 h1:ByW84XTz6W03GSSsygsZcA+xgKK8vPGaa/FCAAEHnAI=
|
||||
github.com/nats-io/nats.go v1.51.0/go.mod h1:26HypzazeOkyO3/mqd1zZd53STJN0EjCYF9Uy2ZOBno=
|
||||
github.com/nats-io/nkeys v0.4.15 h1:JACV5jRVO9V856KOapQ7x+EY8Jo3qw1vJt/9Jpwzkk4=
|
||||
github.com/nats-io/nkeys v0.4.15/go.mod h1:CpMchTXC9fxA5zrMo4KpySxNjiDVvr8ANOSZdiNfUrs=
|
||||
github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw=
|
||||
|
||||
@@ -144,9 +144,8 @@ type Daemon struct {
|
||||
// Delay after QMP device_del before blockdev-del (default 1s, 0 in tests)
|
||||
detachDelay time.Duration
|
||||
|
||||
// NATS connect retry parameters (zero values use defaults: 5min max, 500ms initial delay)
|
||||
natsMaxWait time.Duration
|
||||
natsRetryDelay time.Duration
|
||||
// NATS connect retry options (nil uses defaults: 5min max, 500ms initial delay)
|
||||
natsRetryOpts []utils.RetryOption
|
||||
|
||||
// NetworkPlumber handles tap device lifecycle for VPC networking
|
||||
networkPlumber NetworkPlumber
|
||||
@@ -839,40 +838,12 @@ func (d *Daemon) Start() error {
|
||||
// be ready immediately after daemon start (e.g. if start-dev.sh is still
|
||||
// launching services). This retries for up to 5 minutes before giving up.
|
||||
func (d *Daemon) connectNATS() error {
|
||||
maxWait := 5 * time.Minute
|
||||
retryDelay := 500 * time.Millisecond
|
||||
if d.natsMaxWait > 0 {
|
||||
maxWait = d.natsMaxWait
|
||||
}
|
||||
if d.natsRetryDelay > 0 {
|
||||
retryDelay = d.natsRetryDelay
|
||||
}
|
||||
start := time.Now()
|
||||
|
||||
for {
|
||||
nc, err := utils.ConnectNATS(d.config.NATS.Host, d.config.NATS.ACL.Token, d.config.NATS.CACert)
|
||||
if err == nil {
|
||||
d.natsConn = nc
|
||||
if time.Since(start) > time.Second {
|
||||
slog.Info("NATS connection established", "elapsed", time.Since(start))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// TLS configuration errors are permanent — retrying will not help.
|
||||
if strings.Contains(err.Error(), "CA cert") {
|
||||
return fmt.Errorf("NATS TLS configuration error: %w", err)
|
||||
}
|
||||
|
||||
elapsed := time.Since(start)
|
||||
if elapsed >= maxWait {
|
||||
return fmt.Errorf("NATS connect failed after %s: %w", elapsed.Round(time.Second), err)
|
||||
}
|
||||
|
||||
slog.Warn("NATS not ready, retrying...", "error", err, "elapsed", elapsed.Round(time.Second), "retryIn", retryDelay)
|
||||
time.Sleep(retryDelay)
|
||||
retryDelay = min(retryDelay*2, 10*time.Second)
|
||||
nc, err := utils.ConnectNATSWithRetry(d.config.NATS.Host, d.config.NATS.ACL.Token, d.config.NATS.CACert, d.natsRetryOpts...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
d.natsConn = nc
|
||||
return nil
|
||||
}
|
||||
|
||||
// initJetStream initializes JetStream with retry/backoff and upgrades replicas
|
||||
@@ -2817,7 +2788,7 @@ func (d *Daemon) wireLBAgentConfig() {
|
||||
}
|
||||
|
||||
if d.mgmtBridgeIP != "" {
|
||||
if awsgwBindIP != "" && awsgwBindIP != "0.0.0.0" {
|
||||
if awsgwBindIP != "" && awsgwBindIP != "0.0.0.0" && !net.ParseIP(awsgwBindIP).IsLoopback() {
|
||||
// Multi-node: AWSGW listens on a specific WAN IP. Use that IP
|
||||
// as the gateway URL. Internal LBs will get a host route via
|
||||
// br-mgmt to reach it (see LaunchSystemInstance).
|
||||
|
||||
@@ -153,26 +153,70 @@ func (d *Daemon) LaunchSystemInstance(input *handlers_elbv2.SystemInstanceInput)
|
||||
}
|
||||
}
|
||||
|
||||
// Allocate public IP for internet-facing ALBs
|
||||
// Allocate public IP for internet-facing ALBs. Route through the EIP
|
||||
// service when available so an EIPRecord is created in the KV bucket —
|
||||
// otherwise AWS SDK callers (OpenTofu) can't observe the EIP via
|
||||
// DescribeAddresses and their provisioning flow hangs. Falls back to
|
||||
// direct IPAM allocation for daemons where the EIP service isn't wired.
|
||||
publicIP := ""
|
||||
if input.Scheme == handlers_elbv2.SchemeInternetFacing && d.externalIPAM != nil && d.vpcService != nil && instance.ENIId != "" {
|
||||
region := ""
|
||||
az := ""
|
||||
if d.config != nil {
|
||||
region = d.config.Region
|
||||
az = d.config.AZ
|
||||
}
|
||||
allocatedIP, poolName, allocErr := d.externalIPAM.AllocateIP(region, az, "auto_assign", "", instance.ENIId, instance.ID)
|
||||
if allocErr != nil {
|
||||
slog.Error("LaunchSystemInstance: failed to allocate public IP for internet-facing ALB", "instanceId", instance.ID, "err", allocErr)
|
||||
d.cleanupFailedSystemInstance(instance, instanceType)
|
||||
return nil, fmt.Errorf("allocate public IP for internet-facing ALB: %w", allocErr)
|
||||
} else {
|
||||
if input.Scheme == handlers_elbv2.SchemeInternetFacing && d.vpcService != nil && instance.ENIId != "" {
|
||||
if d.eipService != nil {
|
||||
allocOut, allocErr := d.eipService.AllocateAddress(&ec2.AllocateAddressInput{}, eniAccountID)
|
||||
if allocErr != nil {
|
||||
slog.Error("LaunchSystemInstance: EIP AllocateAddress failed", "instanceId", instance.ID, "err", allocErr)
|
||||
d.cleanupFailedSystemInstance(instance, instanceType)
|
||||
return nil, fmt.Errorf("allocate public IP for internet-facing ALB: %w", allocErr)
|
||||
}
|
||||
publicIP = aws.StringValue(allocOut.PublicIp)
|
||||
poolName := aws.StringValue(allocOut.PublicIpv4Pool)
|
||||
allocID := aws.StringValue(allocOut.AllocationId)
|
||||
|
||||
assocOut, assocErr := d.eipService.AssociateAddress(&ec2.AssociateAddressInput{
|
||||
AllocationId: allocOut.AllocationId,
|
||||
NetworkInterfaceId: aws.String(instance.ENIId),
|
||||
}, eniAccountID)
|
||||
if assocErr != nil {
|
||||
slog.Error("LaunchSystemInstance: EIP AssociateAddress failed", "instanceId", instance.ID, "allocationId", allocID, "err", assocErr)
|
||||
if _, relErr := d.eipService.ReleaseAddress(&ec2.ReleaseAddressInput{
|
||||
AllocationId: allocOut.AllocationId,
|
||||
}, eniAccountID); relErr != nil {
|
||||
slog.Warn("LaunchSystemInstance: failed to release EIP after associate failure", "allocationId", allocID, "err", relErr)
|
||||
}
|
||||
d.cleanupFailedSystemInstance(instance, instanceType)
|
||||
return nil, fmt.Errorf("associate public IP for internet-facing ALB: %w", assocErr)
|
||||
}
|
||||
|
||||
if updateErr := d.vpcService.UpdateENIPublicIP(eniAccountID, instance.ENIId, publicIP, poolName); updateErr != nil {
|
||||
slog.Warn("LaunchSystemInstance: failed to update ENI with public IP", "eniId", instance.ENIId, "err", updateErr)
|
||||
}
|
||||
instance.PublicIP = publicIP
|
||||
instance.PublicIPPool = poolName
|
||||
instance.PublicIPAllocID = allocID
|
||||
instance.PublicIPAssocID = aws.StringValue(assocOut.AssociationId)
|
||||
slog.Info("LaunchSystemInstance: allocated public IP via EIP service",
|
||||
"instanceId", instance.ID,
|
||||
"publicIp", publicIP,
|
||||
"pool", poolName,
|
||||
"allocationId", allocID,
|
||||
"associationId", instance.PublicIPAssocID,
|
||||
)
|
||||
} else if d.externalIPAM != nil {
|
||||
region := ""
|
||||
az := ""
|
||||
if d.config != nil {
|
||||
region = d.config.Region
|
||||
az = d.config.AZ
|
||||
}
|
||||
allocatedIP, poolName, allocErr := d.externalIPAM.AllocateIP(region, az, "auto_assign", "", instance.ENIId, instance.ID)
|
||||
if allocErr != nil {
|
||||
slog.Error("LaunchSystemInstance: failed to allocate public IP for internet-facing ALB", "instanceId", instance.ID, "err", allocErr)
|
||||
d.cleanupFailedSystemInstance(instance, instanceType)
|
||||
return nil, fmt.Errorf("allocate public IP for internet-facing ALB: %w", allocErr)
|
||||
}
|
||||
publicIP = allocatedIP
|
||||
if updateErr := d.vpcService.UpdateENIPublicIP(eniAccountID, instance.ENIId, publicIP, poolName); updateErr != nil {
|
||||
slog.Warn("LaunchSystemInstance: failed to update ENI with public IP", "eniId", instance.ENIId, "err", updateErr)
|
||||
}
|
||||
// Look up VpcId from the ENI for the NAT event
|
||||
vpcID := ""
|
||||
result, descErr := d.vpcService.DescribeNetworkInterfaces(&ec2.DescribeNetworkInterfacesInput{
|
||||
NetworkInterfaceIds: []*string{aws.String(instance.ENIId)},
|
||||
@@ -184,7 +228,7 @@ func (d *Daemon) LaunchSystemInstance(input *handlers_elbv2.SystemInstanceInput)
|
||||
d.publishNATEvent("vpc.add-nat", vpcID, publicIP, privateIP, portName, instance.ENIMac)
|
||||
instance.PublicIP = publicIP
|
||||
instance.PublicIPPool = poolName
|
||||
slog.Info("LaunchSystemInstance: allocated public IP",
|
||||
slog.Info("LaunchSystemInstance: allocated public IP via direct IPAM",
|
||||
"instanceId", instance.ID,
|
||||
"publicIp", publicIP,
|
||||
"pool", poolName,
|
||||
@@ -316,6 +360,32 @@ func (d *Daemon) TerminateSystemInstance(instanceID string) error {
|
||||
return fmt.Errorf("transition to shutting-down: %w", err)
|
||||
}
|
||||
|
||||
// Release EIP through the EIP service for system VMs whose public IP was
|
||||
// allocated via AllocateAddress (internet-facing ALBs). Clears the fields
|
||||
// so the generic teardown path in stopInstance doesn't try to
|
||||
// double-release the same IP through externalIPAM directly.
|
||||
if instance.PublicIPAllocID != "" && d.eipService != nil {
|
||||
eniAccount := instance.AccountID
|
||||
if instance.PublicIPAssocID != "" {
|
||||
if _, err := d.eipService.DisassociateAddress(&ec2.DisassociateAddressInput{
|
||||
AssociationId: aws.String(instance.PublicIPAssocID),
|
||||
}, eniAccount); err != nil {
|
||||
slog.Warn("TerminateSystemInstance: DisassociateAddress failed", "instanceId", instanceID, "associationId", instance.PublicIPAssocID, "err", err)
|
||||
}
|
||||
}
|
||||
if _, err := d.eipService.ReleaseAddress(&ec2.ReleaseAddressInput{
|
||||
AllocationId: aws.String(instance.PublicIPAllocID),
|
||||
}, eniAccount); err != nil {
|
||||
slog.Warn("TerminateSystemInstance: ReleaseAddress failed", "instanceId", instanceID, "allocationId", instance.PublicIPAllocID, "err", err)
|
||||
} else {
|
||||
slog.Info("TerminateSystemInstance: released EIP", "instanceId", instanceID, "ip", instance.PublicIP, "allocationId", instance.PublicIPAllocID)
|
||||
}
|
||||
instance.PublicIP = ""
|
||||
instance.PublicIPPool = ""
|
||||
instance.PublicIPAllocID = ""
|
||||
instance.PublicIPAssocID = ""
|
||||
}
|
||||
|
||||
// Stop the VM (QEMU shutdown, volume unmount, tap cleanup)
|
||||
if err := d.stopInstance(map[string]*vm.VM{instanceID: instance}, true); err != nil {
|
||||
slog.Error("TerminateSystemInstance: stopInstance failed", "instanceId", instanceID, "err", err)
|
||||
|
||||
@@ -32,6 +32,7 @@ import (
|
||||
"github.com/mulgadc/spinifex/spinifex/objectstore"
|
||||
"github.com/mulgadc/spinifex/spinifex/qmp"
|
||||
"github.com/mulgadc/spinifex/spinifex/types"
|
||||
"github.com/mulgadc/spinifex/spinifex/utils"
|
||||
"github.com/mulgadc/spinifex/spinifex/vm"
|
||||
"github.com/nats-io/nats.go"
|
||||
"github.com/stretchr/testify/assert"
|
||||
@@ -3744,8 +3745,10 @@ func TestConnectNATS_RetriesOnFailure(t *testing.T) {
|
||||
clusterCfg.Nodes["node-1"] = cfg
|
||||
daemon, err := NewDaemon(clusterCfg)
|
||||
require.NoError(t, err)
|
||||
daemon.natsMaxWait = 500 * time.Millisecond
|
||||
daemon.natsRetryDelay = 50 * time.Millisecond
|
||||
daemon.natsRetryOpts = []utils.RetryOption{
|
||||
utils.WithMaxWait(500 * time.Millisecond),
|
||||
utils.WithRetryDelay(50 * time.Millisecond),
|
||||
}
|
||||
|
||||
start := time.Now()
|
||||
err = daemon.connectNATS()
|
||||
|
||||
@@ -102,7 +102,7 @@ func launchService(config *config.ClusterConfig) error {
|
||||
|
||||
// Connect to NATS for service communication. On concurrent startup the
|
||||
// local NATS server may not be listening yet, so retry with backoff.
|
||||
natsConn, err := connectNATS(nodeConfig.NATS.Host, nodeConfig.NATS.ACL.Token, nodeConfig.NATS.CACert)
|
||||
natsConn, err := utils.ConnectNATSWithRetry(nodeConfig.NATS.Host, nodeConfig.NATS.ACL.Token, nodeConfig.NATS.CACert)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -203,38 +203,6 @@ func launchService(config *config.ClusterConfig) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// connectNATS establishes a connection to NATS with retry/backoff. On concurrent
|
||||
// startup the local NATS server may not be listening yet.
|
||||
func connectNATS(host, token, caCertPath string) (*nats.Conn, error) {
|
||||
const maxWait = 5 * time.Minute
|
||||
retryDelay := 500 * time.Millisecond
|
||||
start := time.Now()
|
||||
|
||||
for {
|
||||
nc, err := utils.ConnectNATS(host, token, caCertPath)
|
||||
if err == nil {
|
||||
if time.Since(start) > time.Second {
|
||||
slog.Info("NATS connection established", "elapsed", time.Since(start).Round(time.Second))
|
||||
}
|
||||
return nc, nil
|
||||
}
|
||||
|
||||
// TLS configuration errors are permanent — retrying will not help.
|
||||
if strings.Contains(err.Error(), "CA cert") {
|
||||
return nil, fmt.Errorf("NATS TLS configuration error: %w", err)
|
||||
}
|
||||
|
||||
elapsed := time.Since(start)
|
||||
if elapsed >= maxWait {
|
||||
return nil, fmt.Errorf("NATS connect failed after %s: %w", elapsed.Round(time.Second), err)
|
||||
}
|
||||
|
||||
slog.Warn("NATS not ready, retrying...", "error", err, "elapsed", elapsed.Round(time.Second), "retryIn", retryDelay)
|
||||
time.Sleep(retryDelay)
|
||||
retryDelay = min(retryDelay*2, 10*time.Second)
|
||||
}
|
||||
}
|
||||
|
||||
// initIAMService initializes the IAM service with retry/backoff. On multi-node
|
||||
// clusters, JetStream requires NATS cluster quorum before KV buckets can be
|
||||
// created. This retries for up to 5 minutes to allow late-joining nodes.
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -46,5 +46,5 @@ ${r.join(`;`)}
|
||||
${n}`}async createStringToSign(e,t,n,r){let i=new this.sha256;return i.update(rc(n)),`${r}
|
||||
${e}
|
||||
${t}
|
||||
${$(await i.digest())}`}getCanonicalPath({path:e}){if(this.uriEscapePath){let t=[];for(let n of e.split(`/`))n?.length!==0&&n!==`.`&&(n===`..`?t.pop():t.push(n));return Bc(`${e?.startsWith(`/`)?`/`:``}${t.join(`/`)}${t.length>0&&e?.endsWith(`/`)?`/`:``}`).replace(/%2F/g,`/`)}return e}validateResolvedCredentials(e){if(typeof e!=`object`||typeof e.accessKeyId!=`string`||typeof e.secretAccessKey!=`string`)throw Error(`Resolved credential object is not valid`)}formatDate(e){let t=Uc(e).replace(/[\-:]/g,``);return{longDate:t,shortDate:t.slice(0,8)}}getCanonicalHeaderList(e){return Object.keys(e).sort().join(`;`)}},Kc=class extends Gc{headerFormatter=new jc;constructor({applyChecksum:e,credentials:t,region:n,service:r,sha256:i,uriEscapePath:a=!0}){super({applyChecksum:e,credentials:t,region:n,service:r,sha256:i,uriEscapePath:a})}async presign(e,t={}){let{signingDate:n=new Date,expiresIn:r=3600,unsignableHeaders:i,unhoistableHeaders:a,signableHeaders:o,hoistableHeaders:s,signingRegion:c,signingService:l}=t,u=await this.credentialProvider();this.validateResolvedCredentials(u);let d=c??await this.regionProvider(),{longDate:f,shortDate:p}=this.formatDate(n);if(r>604800)return Promise.reject(`Signature version 4 presigned URLs must have an expiration date less than one week in the future`);let m=Tc(p,d,l??this.service),h=Lc(Rc(e),{unhoistableHeaders:a,hoistableHeaders:s});u.sessionToken&&(h.query[uc]=u.sessionToken),h.query[ic]=yc,h.query[ac]=`${u.accessKeyId}/${m}`,h.query[oc]=f,h.query[cc]=r.toString(10);let g=Oc(h,i,o);return h.query[sc]=this.getCanonicalHeaderList(g),h.query[lc]=await this.getSignature(f,m,this.getSigningKey(u,d,p,l),this.createCanonicalRequest(h,g,await Ac(e,this.sha256))),h}async sign(e,t){return typeof e==`string`?this.signString(e,t):e.headers&&e.payload?this.signEvent(e,t):e.message?this.signMessage(e,t):this.signRequest(e,t)}async signEvent({headers:e,payload:t},{signingDate:n=new Date,priorSignature:r,signingRegion:i,signingService:a}){let o=i??await this.regionProvider(),{shortDate:s,longDate:c}=this.formatDate(n),l=Tc(s,o,a??this.service),u=await Ac({headers:{},body:t},this.sha256),d=new this.sha256;d.update(e);let f=[bc,c,l,r,$(await d.digest()),u].join(`
|
||||
`);return this.signString(f,{signingDate:n,signingRegion:o,signingService:a})}async signMessage(e,{signingDate:t=new Date,signingRegion:n,signingService:r}){return this.signEvent({headers:this.headerFormatter.format(e.message.headers),payload:e.message.body},{signingDate:t,signingRegion:n,signingService:r,priorSignature:e.priorSignature}).then(t=>({message:e.message,signature:t}))}async signString(e,{signingDate:t=new Date,signingRegion:n,signingService:r}={}){let i=await this.credentialProvider();this.validateResolvedCredentials(i);let a=n??await this.regionProvider(),{shortDate:o}=this.formatDate(t),s=new this.sha256(await this.getSigningKey(i,a,o,r));return s.update(rc(e)),$(await s.digest())}async signRequest(e,{signingDate:t=new Date,signableHeaders:n,unsignableHeaders:r,signingRegion:i,signingService:a}={}){let o=await this.credentialProvider();this.validateResolvedCredentials(o);let s=i??await this.regionProvider(),c=Rc(e),{longDate:l,shortDate:u}=this.formatDate(t),d=Tc(u,s,a??this.service);c.headers[fc]=l,o.sessionToken&&(c.headers[hc]=o.sessionToken);let f=await Ac(c,this.sha256);!Ic(`x-amz-content-sha256`,c.headers)&&this.applyChecksum&&(c.headers[mc]=f);let p=Oc(c,r,n),m=await this.getSignature(l,d,this.getSigningKey(o,s,u,a),this.createCanonicalRequest(c,p,f));return c.headers[dc]=`${yc} Credential=${o.accessKeyId}/${d}, SignedHeaders=${this.getCanonicalHeaderList(p)}, Signature=${m}`,c}async getSignature(e,t,n,r){let i=await this.createStringToSign(e,t,r,yc),a=new this.sha256(await n);return a.update(rc(i)),$(await a.digest())}getSigningKey(e,t,n,r){return Ec(this.sha256,e,n,t,r||this.service)}};export{Yo as A,Ze as B,ws as C,No as D,Fo as E,nt as F,et as H,qe as I,tt as L,Ut as M,Gt as N,jo as O,Rt as P,rt as R,Cs as S,Vo as T,n as U,Qe as V,ks as _,rc as a,Ss as b,Qs as c,Rs as d,zs as f,As as g,js as h,kc as i,lo as j,Uo as k,Zs as l,Is as m,Bc as n,nc as o,Bs as p,zc as r,$ as s,Kc as t,Js as u,Os as v,Zo as w,Ts as x,Es as y,Ye as z};
|
||||
${$(await i.digest())}`}getCanonicalPath({path:e}){if(this.uriEscapePath){let t=[];for(let n of e.split(`/`))n?.length!==0&&n!==`.`&&(n===`..`?t.pop():t.push(n));return Bc(`${e?.startsWith(`/`)?`/`:``}${t.join(`/`)}${t.length>0&&e?.endsWith(`/`)?`/`:``}`).replace(/%2F/g,`/`)}return e}validateResolvedCredentials(e){if(typeof e!=`object`||typeof e.accessKeyId!=`string`||typeof e.secretAccessKey!=`string`)throw Error(`Resolved credential object is not valid`)}formatDate(e){let t=Uc(e).replace(/[\-:]/g,``);return{longDate:t,shortDate:t.slice(0,8)}}getCanonicalHeaderList(e){return Object.keys(e).sort().join(`;`)}},Kc=class extends Gc{headerFormatter=new jc;constructor({applyChecksum:e,credentials:t,region:n,service:r,sha256:i,uriEscapePath:a=!0}){super({applyChecksum:e,credentials:t,region:n,service:r,sha256:i,uriEscapePath:a})}async presign(e,t={}){let{signingDate:n=new Date,expiresIn:r=3600,unsignableHeaders:i,unhoistableHeaders:a,signableHeaders:o,hoistableHeaders:s,signingRegion:c,signingService:l}=t,u=await this.credentialProvider();this.validateResolvedCredentials(u);let d=c??await this.regionProvider(),{longDate:f,shortDate:p}=this.formatDate(n);if(r>604800)return Promise.reject(`Signature version 4 presigned URLs must have an expiration date less than one week in the future`);let m=Tc(p,d,l??this.service),h=Lc(Rc(e),{unhoistableHeaders:a,hoistableHeaders:s});u.sessionToken&&(h.query[uc]=u.sessionToken),h.query[ic]=yc,h.query[ac]=`${u.accessKeyId}/${m}`,h.query[oc]=f,h.query[cc]=r.toString(10);let g=Oc(h,i,o);return h.query[sc]=this.getCanonicalHeaderList(g),h.query[lc]=await this.getSignature(f,m,this.getSigningKey(u,d,p,l),this.createCanonicalRequest(h,g,await Ac(e,this.sha256))),h}async sign(e,t){return typeof e==`string`?this.signString(e,t):e.headers&&e.payload?this.signEvent(e,t):e.message?this.signMessage(e,t):this.signRequest(e,t)}async signEvent({headers:e,payload:t},{signingDate:n=new Date,priorSignature:r,signingRegion:i,signingService:a,eventStreamCredentials:o}){let s=i??await this.regionProvider(),{shortDate:c,longDate:l}=this.formatDate(n),u=Tc(c,s,a??this.service),d=await Ac({headers:{},body:t},this.sha256),f=new this.sha256;f.update(e);let p=[bc,l,u,r,$(await f.digest()),d].join(`
|
||||
`);return this.signString(p,{signingDate:n,signingRegion:s,signingService:a,eventStreamCredentials:o})}async signMessage(e,{signingDate:t=new Date,signingRegion:n,signingService:r,eventStreamCredentials:i}){return this.signEvent({headers:this.headerFormatter.format(e.message.headers),payload:e.message.body},{signingDate:t,signingRegion:n,signingService:r,priorSignature:e.priorSignature,eventStreamCredentials:i}).then(t=>({message:e.message,signature:t}))}async signString(e,{signingDate:t=new Date,signingRegion:n,signingService:r,eventStreamCredentials:i}={}){let a=i??await this.credentialProvider();this.validateResolvedCredentials(a);let o=n??await this.regionProvider(),{shortDate:s}=this.formatDate(t),c=new this.sha256(await this.getSigningKey(a,o,s,r));return c.update(rc(e)),$(await c.digest())}async signRequest(e,{signingDate:t=new Date,signableHeaders:n,unsignableHeaders:r,signingRegion:i,signingService:a}={}){let o=await this.credentialProvider();this.validateResolvedCredentials(o);let s=i??await this.regionProvider(),c=Rc(e),{longDate:l,shortDate:u}=this.formatDate(t),d=Tc(u,s,a??this.service);c.headers[fc]=l,o.sessionToken&&(c.headers[hc]=o.sessionToken);let f=await Ac(c,this.sha256);!Ic(`x-amz-content-sha256`,c.headers)&&this.applyChecksum&&(c.headers[mc]=f);let p=Oc(c,r,n),m=await this.getSignature(l,d,this.getSigningKey(o,s,u,a),this.createCanonicalRequest(c,p,f));return c.headers[dc]=`${yc} Credential=${o.accessKeyId}/${d}, SignedHeaders=${this.getCanonicalHeaderList(p)}, Signature=${m}`,c}async getSignature(e,t,n,r){let i=await this.createStringToSign(e,t,r,yc),a=new this.sha256(await n);return a.update(rc(i)),$(await a.digest())}getSigningKey(e,t,n,r){return Ec(this.sha256,e,n,t,r||this.service)}};export{Yo as A,Ze as B,ws as C,No as D,Fo as E,nt as F,et as H,qe as I,tt as L,Ut as M,Gt as N,jo as O,Rt as P,rt as R,Cs as S,Vo as T,n as U,Qe as V,ks as _,rc as a,Ss as b,Qs as c,Rs as d,zs as f,As as g,js as h,kc as i,lo as j,Uo as k,Zs as l,Is as m,Bc as n,nc as o,Bs as p,zc as r,$ as s,Kc as t,Js as u,Os as v,Zo as w,Ts as x,Es as y,Ye as z};
|
||||
+1
-1
@@ -1,2 +1,2 @@
|
||||
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/_2.js","assets/compiler-runtime.js","assets/s3.js","assets/awsClient.js","assets/SignatureV4.js","assets/fromUtf8.browser.js","assets/toUtf8.browser.js","assets/QueryClientProvider.js","assets/error-banner.js","assets/mutation.js","assets/upload-button.js","assets/button.js","assets/dist.js","assets/link.js","assets/useStore.js","assets/createLucideIcon.js","assets/download.js","assets/trash-2.js","assets/delete-confirmation-dialog.js","assets/alert-dialog.js","assets/DialogTitle.js","assets/useOpenInteractionType.js","assets/createBaseUIEventDetails.js","assets/useTransitionStatus.js","assets/s32.js","assets/queryOptions.js","assets/useSuspenseQuery.js","assets/useBaseQuery.js","assets/query.js","assets/back-link.js"])))=>i.map(i=>d[i]);
|
||||
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/_2.js","assets/compiler-runtime.js","assets/s3.js","assets/awsClient.js","assets/SignatureV4.js","assets/fromUtf8.browser.js","assets/toUtf8.browser.js","assets/QueryClientProvider.js","assets/error-banner.js","assets/mutation.js","assets/upload-button.js","assets/button.js","assets/dist.js","assets/link.js","assets/useStore.js","assets/createLucideIcon.js","assets/download.js","assets/trash-2.js","assets/delete-confirmation-dialog.js","assets/alert-dialog.js","assets/DialogTitle.js","assets/useOpenInteractionType.js","assets/createBaseUIEventDetails.js","assets/addEventListener.js","assets/s32.js","assets/queryOptions.js","assets/useSuspenseQuery.js","assets/useBaseQuery.js","assets/query.js","assets/back-link.js"])))=>i.map(i=>d[i]);
|
||||
import{n as e,t}from"./lazyRouteComponent.js";import{cn as n}from"./awsClient.js";import{F as r,L as i}from"./SignatureV4.js";import{t as a}from"./s32.js";var o=e(`/_auth/s3/ls/$bucket/$`)({loader:async({context:e,params:t})=>{let n=i(t._splat??``);await e.queryClient.ensureQueryData(a(t.bucket,n))},head:({params:e})=>({meta:[{title:`${r(e._splat??``,`${e.bucket}/`)} | S3 | Mulga`}]}),component:t(()=>n(()=>import(`./_2.js`),__vite__mapDeps([0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29])),`component`)});export{o as t};
|
||||
@@ -1,2 +1,2 @@
|
||||
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/_bucket2.js","assets/compiler-runtime.js","assets/s3.js","assets/awsClient.js","assets/SignatureV4.js","assets/fromUtf8.browser.js","assets/toUtf8.browser.js","assets/QueryClientProvider.js","assets/error-banner.js","assets/mutation.js","assets/upload-button.js","assets/button.js","assets/dist.js","assets/link.js","assets/useStore.js","assets/createLucideIcon.js","assets/download.js","assets/trash-2.js","assets/delete-confirmation-dialog.js","assets/alert-dialog.js","assets/DialogTitle.js","assets/useOpenInteractionType.js","assets/createBaseUIEventDetails.js","assets/useTransitionStatus.js","assets/s32.js","assets/queryOptions.js","assets/useSuspenseQuery.js","assets/useBaseQuery.js","assets/query.js","assets/back-link.js","assets/page-heading.js"])))=>i.map(i=>d[i]);
|
||||
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/_bucket2.js","assets/compiler-runtime.js","assets/s3.js","assets/awsClient.js","assets/SignatureV4.js","assets/fromUtf8.browser.js","assets/toUtf8.browser.js","assets/QueryClientProvider.js","assets/error-banner.js","assets/mutation.js","assets/upload-button.js","assets/button.js","assets/dist.js","assets/link.js","assets/useStore.js","assets/createLucideIcon.js","assets/download.js","assets/trash-2.js","assets/delete-confirmation-dialog.js","assets/alert-dialog.js","assets/DialogTitle.js","assets/useOpenInteractionType.js","assets/createBaseUIEventDetails.js","assets/addEventListener.js","assets/s32.js","assets/queryOptions.js","assets/useSuspenseQuery.js","assets/useBaseQuery.js","assets/query.js","assets/back-link.js","assets/page-heading.js"])))=>i.map(i=>d[i]);
|
||||
import{n as e,t}from"./lazyRouteComponent.js";import{cn as n}from"./awsClient.js";import{t as r}from"./s32.js";var i=e(`/_auth/s3/ls/$bucket/`)({loader:async({context:e,params:t})=>{await e.queryClient.ensureQueryData(r(t.bucket))},head:({params:e})=>({meta:[{title:`${e.bucket} | S3 | Mulga`}]}),component:t(()=>n(()=>import(`./_bucket2.js`),__vite__mapDeps([0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30])),`component`)});export{i as t};
|
||||
@@ -1,2 +1,2 @@
|
||||
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/_id22.js","assets/compiler-runtime.js","assets/SignatureV4.js","assets/fromUtf8.browser.js","assets/ec2.js","assets/awsClient.js","assets/toUtf8.browser.js","assets/ec22.js","assets/DescribeInstancesCommand.js","assets/queryOptions.js","assets/QueryClientProvider.js","assets/error-banner.js","assets/mutation.js","assets/alert-dialog.js","assets/button.js","assets/dist.js","assets/DialogTitle.js","assets/useOpenInteractionType.js","assets/createBaseUIEventDetails.js","assets/useTransitionStatus.js","assets/useStore.js","assets/select.js","assets/getDisabledMountTransitionStyles.js","assets/separator.js","assets/createLucideIcon.js","assets/check.js","assets/chevron-down.js","assets/input.js","assets/useSuspenseQuery.js","assets/useBaseQuery.js","assets/query.js","assets/link.js","assets/useNavigate.js","assets/back-link.js","assets/trash-2.js","assets/delete-confirmation-dialog.js","assets/detail-row.js","assets/page-heading.js","assets/state-badge.js","assets/field.js"])))=>i.map(i=>d[i]);
|
||||
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/_id22.js","assets/compiler-runtime.js","assets/SignatureV4.js","assets/fromUtf8.browser.js","assets/ec2.js","assets/awsClient.js","assets/toUtf8.browser.js","assets/ec22.js","assets/DescribeInstancesCommand.js","assets/queryOptions.js","assets/QueryClientProvider.js","assets/error-banner.js","assets/mutation.js","assets/alert-dialog.js","assets/button.js","assets/dist.js","assets/DialogTitle.js","assets/useOpenInteractionType.js","assets/createBaseUIEventDetails.js","assets/addEventListener.js","assets/useStore.js","assets/select.js","assets/usePositioner.js","assets/separator.js","assets/createLucideIcon.js","assets/check.js","assets/chevron-down.js","assets/input.js","assets/useSuspenseQuery.js","assets/useBaseQuery.js","assets/query.js","assets/link.js","assets/useNavigate.js","assets/back-link.js","assets/trash-2.js","assets/delete-confirmation-dialog.js","assets/detail-row.js","assets/page-heading.js","assets/state-badge.js","assets/field.js"])))=>i.map(i=>d[i]);
|
||||
import{n as e,t}from"./lazyRouteComponent.js";import{cn as n}from"./awsClient.js";import{t as r}from"./createLucideIcon.js";import{o as i,v as a}from"./ec22.js";var o=r(`camera`,[[`path`,{d:`M13.997 4a2 2 0 0 1 1.76 1.05l.486.9A2 2 0 0 0 18.003 7H20a2 2 0 0 1 2 2v9a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V9a2 2 0 0 1 2-2h1.997a2 2 0 0 0 1.759-1.048l.489-.904A2 2 0 0 1 10.004 4z`,key:`18u6gg`}],[`circle`,{cx:`12`,cy:`13`,r:`3`,key:`1vg3eu`}]]),s=e(`/_auth/ec2/(volumes)/describe-volumes/$id`)({loader:async({context:e,params:t})=>{await Promise.all([e.queryClient.ensureQueryData(a(t.id)),e.queryClient.ensureQueryData(i)])},head:({params:e})=>({meta:[{title:`${e.id} | EC2 | Mulga`}]}),component:t(()=>n(()=>import(`./_id22.js`),__vite__mapDeps([0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39])),`component`)});export{o as n,s as t};
|
||||
@@ -1,2 +1,2 @@
|
||||
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/_id15.js","assets/compiler-runtime.js","assets/SignatureV4.js","assets/fromUtf8.browser.js","assets/ec2.js","assets/awsClient.js","assets/toUtf8.browser.js","assets/ec22.js","assets/DescribeInstancesCommand.js","assets/queryOptions.js","assets/QueryClientProvider.js","assets/error-banner.js","assets/mutation.js","assets/button.js","assets/dist.js","assets/useSuspenseQuery.js","assets/useBaseQuery.js","assets/query.js","assets/useNavigate.js","assets/useStore.js","assets/back-link.js","assets/link.js","assets/createLucideIcon.js","assets/trash-2.js","assets/delete-confirmation-dialog.js","assets/alert-dialog.js","assets/DialogTitle.js","assets/useOpenInteractionType.js","assets/createBaseUIEventDetails.js","assets/useTransitionStatus.js","assets/detail-row.js","assets/page-heading.js"])))=>i.map(i=>d[i]);
|
||||
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/_id15.js","assets/compiler-runtime.js","assets/SignatureV4.js","assets/fromUtf8.browser.js","assets/ec2.js","assets/awsClient.js","assets/toUtf8.browser.js","assets/ec22.js","assets/DescribeInstancesCommand.js","assets/queryOptions.js","assets/QueryClientProvider.js","assets/error-banner.js","assets/mutation.js","assets/button.js","assets/dist.js","assets/useSuspenseQuery.js","assets/useBaseQuery.js","assets/query.js","assets/useNavigate.js","assets/useStore.js","assets/back-link.js","assets/link.js","assets/createLucideIcon.js","assets/trash-2.js","assets/delete-confirmation-dialog.js","assets/alert-dialog.js","assets/DialogTitle.js","assets/useOpenInteractionType.js","assets/createBaseUIEventDetails.js","assets/addEventListener.js","assets/detail-row.js","assets/page-heading.js"])))=>i.map(i=>d[i]);
|
||||
import{n as e,t}from"./lazyRouteComponent.js";import{cn as n}from"./awsClient.js";import{s as r}from"./ec22.js";var i=e(`/_auth/ec2/(key)/describe-key-pairs/$id`)({loader:async({context:e,params:t})=>await e.queryClient.ensureQueryData(r(t.id)),head:({loaderData:e})=>({meta:[{title:`${e?.KeyPairs?.[0]?.KeyName??`Key Pair`} | EC2 | Mulga`}]}),component:t(()=>n(()=>import(`./_id15.js`),__vite__mapDeps([0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31])),`component`)});export{i as t};
|
||||
@@ -1,2 +1,2 @@
|
||||
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/_id14.js","assets/compiler-runtime.js","assets/SignatureV4.js","assets/fromUtf8.browser.js","assets/ec2.js","assets/awsClient.js","assets/toUtf8.browser.js","assets/ec22.js","assets/DescribeInstancesCommand.js","assets/queryOptions.js","assets/QueryClientProvider.js","assets/error-banner.js","assets/mutation.js","assets/alert-dialog.js","assets/button.js","assets/dist.js","assets/DialogTitle.js","assets/useOpenInteractionType.js","assets/createBaseUIEventDetails.js","assets/useTransitionStatus.js","assets/useStore.js","assets/select.js","assets/getDisabledMountTransitionStyles.js","assets/separator.js","assets/createLucideIcon.js","assets/check.js","assets/chevron-down.js","assets/input.js","assets/useSuspenseQuery.js","assets/useBaseQuery.js","assets/query.js","assets/link.js","assets/back-link.js","assets/trash-2.js","assets/detail-row.js","assets/page-heading.js","assets/state-badge.js","assets/field.js","assets/textarea.js","assets/ami-details.js"])))=>i.map(i=>d[i]);
|
||||
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/_id14.js","assets/compiler-runtime.js","assets/SignatureV4.js","assets/fromUtf8.browser.js","assets/ec2.js","assets/awsClient.js","assets/toUtf8.browser.js","assets/ec22.js","assets/DescribeInstancesCommand.js","assets/queryOptions.js","assets/QueryClientProvider.js","assets/error-banner.js","assets/mutation.js","assets/alert-dialog.js","assets/button.js","assets/dist.js","assets/DialogTitle.js","assets/useOpenInteractionType.js","assets/createBaseUIEventDetails.js","assets/addEventListener.js","assets/useStore.js","assets/select.js","assets/usePositioner.js","assets/separator.js","assets/createLucideIcon.js","assets/check.js","assets/chevron-down.js","assets/input.js","assets/useSuspenseQuery.js","assets/useBaseQuery.js","assets/query.js","assets/link.js","assets/back-link.js","assets/trash-2.js","assets/detail-row.js","assets/page-heading.js","assets/state-badge.js","assets/field.js","assets/textarea.js","assets/ami-details.js"])))=>i.map(i=>d[i]);
|
||||
import{n as e,t}from"./lazyRouteComponent.js";import{cn as n}from"./awsClient.js";import{a as r,i,n as a}from"./ec22.js";var o=e(`/_auth/ec2/(instances)/describe-instances/$id`)({loader:async({context:e,params:t})=>{let[n]=await Promise.all([e.queryClient.ensureQueryData(i(t.id)),e.queryClient.ensureQueryData(r)]),o=n.Reservations?.[0]?.Instances?.[0]?.ImageId;return await e.queryClient.ensureQueryData(a(o)),n},head:({loaderData:e})=>({meta:[{title:`${e?.Reservations?.[0]?.Instances?.[0]?.InstanceId??`Instance`} | EC2 | Mulga`}]}),component:t(()=>n(()=>import(`./_id14.js`),__vite__mapDeps([0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39])),`component`)});export{o as t};
|
||||
@@ -1,2 +1,2 @@
|
||||
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/_id18.js","assets/compiler-runtime.js","assets/ec2.js","assets/awsClient.js","assets/SignatureV4.js","assets/fromUtf8.browser.js","assets/toUtf8.browser.js","assets/ec22.js","assets/DescribeInstancesCommand.js","assets/queryOptions.js","assets/QueryClientProvider.js","assets/error-banner.js","assets/mutation.js","assets/alert-dialog.js","assets/button.js","assets/dist.js","assets/DialogTitle.js","assets/useOpenInteractionType.js","assets/createBaseUIEventDetails.js","assets/useTransitionStatus.js","assets/useStore.js","assets/select.js","assets/getDisabledMountTransitionStyles.js","assets/separator.js","assets/createLucideIcon.js","assets/check.js","assets/chevron-down.js","assets/input.js","assets/zod.js","assets/useSuspenseQuery.js","assets/useBaseQuery.js","assets/query.js","assets/link.js","assets/useNavigate.js","assets/back-link.js","assets/plus.js","assets/trash-2.js","assets/delete-confirmation-dialog.js","assets/detail-row.js","assets/page-heading.js","assets/field.js","assets/ec23.js"])))=>i.map(i=>d[i]);
|
||||
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/_id18.js","assets/compiler-runtime.js","assets/ec2.js","assets/awsClient.js","assets/SignatureV4.js","assets/fromUtf8.browser.js","assets/toUtf8.browser.js","assets/ec22.js","assets/DescribeInstancesCommand.js","assets/queryOptions.js","assets/QueryClientProvider.js","assets/error-banner.js","assets/mutation.js","assets/alert-dialog.js","assets/button.js","assets/dist.js","assets/DialogTitle.js","assets/useOpenInteractionType.js","assets/createBaseUIEventDetails.js","assets/addEventListener.js","assets/useStore.js","assets/select.js","assets/usePositioner.js","assets/separator.js","assets/createLucideIcon.js","assets/check.js","assets/chevron-down.js","assets/input.js","assets/zod.js","assets/useSuspenseQuery.js","assets/useBaseQuery.js","assets/query.js","assets/link.js","assets/useNavigate.js","assets/back-link.js","assets/plus.js","assets/trash-2.js","assets/delete-confirmation-dialog.js","assets/detail-row.js","assets/page-heading.js","assets/field.js","assets/ec23.js"])))=>i.map(i=>d[i]);
|
||||
import{n as e,t}from"./lazyRouteComponent.js";import{cn as n}from"./awsClient.js";import{t as r}from"./createLucideIcon.js";import{f as i}from"./ec22.js";var a=r(`x`,[[`path`,{d:`M18 6 6 18`,key:`1bl5f8`}],[`path`,{d:`m6 6 12 12`,key:`d8bk6v`}]]),o=e(`/_auth/ec2/(security-groups)/describe-security-groups/$id`)({loader:async({context:e,params:t})=>{await e.queryClient.ensureQueryData(i(t.id))},head:({params:e})=>({meta:[{title:`${e.id} | Security Group | Mulga`}]}),component:t(()=>n(()=>import(`./_id18.js`),__vite__mapDeps([0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41])),`component`)});export{a as n,o as t};
|
||||
@@ -1,2 +1,2 @@
|
||||
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/_id24.js","assets/compiler-runtime.js","assets/SignatureV4.js","assets/fromUtf8.browser.js","assets/ec2.js","assets/awsClient.js","assets/toUtf8.browser.js","assets/ec22.js","assets/DescribeInstancesCommand.js","assets/queryOptions.js","assets/QueryClientProvider.js","assets/error-banner.js","assets/mutation.js","assets/button.js","assets/dist.js","assets/useSuspenseQuery.js","assets/useBaseQuery.js","assets/query.js","assets/link.js","assets/useStore.js","assets/useNavigate.js","assets/back-link.js","assets/createLucideIcon.js","assets/trash-2.js","assets/delete-confirmation-dialog.js","assets/alert-dialog.js","assets/DialogTitle.js","assets/useOpenInteractionType.js","assets/createBaseUIEventDetails.js","assets/useTransitionStatus.js","assets/detail-row.js","assets/page-heading.js","assets/state-badge.js"])))=>i.map(i=>d[i]);
|
||||
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/_id24.js","assets/compiler-runtime.js","assets/SignatureV4.js","assets/fromUtf8.browser.js","assets/ec2.js","assets/awsClient.js","assets/toUtf8.browser.js","assets/ec22.js","assets/DescribeInstancesCommand.js","assets/queryOptions.js","assets/QueryClientProvider.js","assets/error-banner.js","assets/mutation.js","assets/button.js","assets/dist.js","assets/useSuspenseQuery.js","assets/useBaseQuery.js","assets/query.js","assets/link.js","assets/useStore.js","assets/useNavigate.js","assets/back-link.js","assets/createLucideIcon.js","assets/trash-2.js","assets/delete-confirmation-dialog.js","assets/alert-dialog.js","assets/DialogTitle.js","assets/useOpenInteractionType.js","assets/createBaseUIEventDetails.js","assets/addEventListener.js","assets/detail-row.js","assets/page-heading.js","assets/state-badge.js"])))=>i.map(i=>d[i]);
|
||||
import{n as e,t}from"./lazyRouteComponent.js";import{cn as n}from"./awsClient.js";import{_ as r,b as i}from"./ec22.js";var a=e(`/_auth/ec2/(vpc)/describe-vpcs/$id`)({loader:async({context:e,params:t})=>{await Promise.all([e.queryClient.ensureQueryData(i(t.id)),e.queryClient.ensureQueryData(r)])},head:({params:e})=>({meta:[{title:`${e.id} | VPC | Mulga`}]}),component:t(()=>n(()=>import(`./_id24.js`),__vite__mapDeps([0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32])),`component`)});export{a as t};
|
||||
@@ -1,2 +1,2 @@
|
||||
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/_id21.js","assets/compiler-runtime.js","assets/SignatureV4.js","assets/fromUtf8.browser.js","assets/ec22.js","assets/awsClient.js","assets/toUtf8.browser.js","assets/DescribeInstancesCommand.js","assets/queryOptions.js","assets/elbv2.js","assets/QueryClientProvider.js","assets/error-banner.js","assets/mutation.js","assets/elbv22.js","assets/alert-dialog.js","assets/button.js","assets/dist.js","assets/DialogTitle.js","assets/useOpenInteractionType.js","assets/createBaseUIEventDetails.js","assets/useTransitionStatus.js","assets/useStore.js","assets/tabs.js","assets/select.js","assets/getDisabledMountTransitionStyles.js","assets/separator.js","assets/createLucideIcon.js","assets/check.js","assets/chevron-down.js","assets/input.js","assets/field.js","assets/useQuery.js","assets/useBaseQuery.js","assets/query.js","assets/useSuspenseQuery.js","assets/useNavigate.js","assets/back-link.js","assets/link.js","assets/trash-2.js","assets/delete-confirmation-dialog.js","assets/detail-row.js","assets/page-heading.js"])))=>i.map(i=>d[i]);
|
||||
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/_id21.js","assets/compiler-runtime.js","assets/SignatureV4.js","assets/fromUtf8.browser.js","assets/ec22.js","assets/awsClient.js","assets/toUtf8.browser.js","assets/DescribeInstancesCommand.js","assets/queryOptions.js","assets/elbv2.js","assets/QueryClientProvider.js","assets/error-banner.js","assets/mutation.js","assets/elbv22.js","assets/alert-dialog.js","assets/button.js","assets/dist.js","assets/DialogTitle.js","assets/useOpenInteractionType.js","assets/createBaseUIEventDetails.js","assets/addEventListener.js","assets/useStore.js","assets/tabs.js","assets/select.js","assets/usePositioner.js","assets/separator.js","assets/createLucideIcon.js","assets/check.js","assets/chevron-down.js","assets/input.js","assets/field.js","assets/useQuery.js","assets/useBaseQuery.js","assets/query.js","assets/useSuspenseQuery.js","assets/useNavigate.js","assets/back-link.js","assets/link.js","assets/trash-2.js","assets/delete-confirmation-dialog.js","assets/detail-row.js","assets/page-heading.js"])))=>i.map(i=>d[i]);
|
||||
import{n as e,t}from"./lazyRouteComponent.js";import{cn as n}from"./awsClient.js";import{o as r}from"./ec22.js";import{a as i,o as a,s as o}from"./elbv22.js";var s=e(`/_auth/ec2/(target-groups)/describe-target-groups/$id`)({loader:async({context:e,params:t})=>{let n=decodeURIComponent(t.id);await Promise.all([e.queryClient.ensureQueryData(o(n)),e.queryClient.ensureQueryData(a(n)),e.queryClient.ensureQueryData(i([n])),e.queryClient.ensureQueryData(r)])},head:({params:e})=>({meta:[{title:`${decodeURIComponent(e.id)} | Target Group | Mulga`}]}),component:t(()=>n(()=>import(`./_id21.js`),__vite__mapDeps([0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41])),`component`)});export{s as t};
|
||||
@@ -1,2 +1,2 @@
|
||||
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/_id20.js","assets/compiler-runtime.js","assets/SignatureV4.js","assets/fromUtf8.browser.js","assets/ec2.js","assets/awsClient.js","assets/toUtf8.browser.js","assets/ec22.js","assets/DescribeInstancesCommand.js","assets/queryOptions.js","assets/QueryClientProvider.js","assets/error-banner.js","assets/mutation.js","assets/button.js","assets/dist.js","assets/useSuspenseQuery.js","assets/useBaseQuery.js","assets/query.js","assets/link.js","assets/useStore.js","assets/useNavigate.js","assets/back-link.js","assets/createLucideIcon.js","assets/trash-2.js","assets/delete-confirmation-dialog.js","assets/alert-dialog.js","assets/DialogTitle.js","assets/useOpenInteractionType.js","assets/createBaseUIEventDetails.js","assets/useTransitionStatus.js","assets/detail-row.js","assets/page-heading.js","assets/state-badge.js"])))=>i.map(i=>d[i]);
|
||||
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/_id20.js","assets/compiler-runtime.js","assets/SignatureV4.js","assets/fromUtf8.browser.js","assets/ec2.js","assets/awsClient.js","assets/toUtf8.browser.js","assets/ec22.js","assets/DescribeInstancesCommand.js","assets/queryOptions.js","assets/QueryClientProvider.js","assets/error-banner.js","assets/mutation.js","assets/button.js","assets/dist.js","assets/useSuspenseQuery.js","assets/useBaseQuery.js","assets/query.js","assets/link.js","assets/useStore.js","assets/useNavigate.js","assets/back-link.js","assets/createLucideIcon.js","assets/trash-2.js","assets/delete-confirmation-dialog.js","assets/alert-dialog.js","assets/DialogTitle.js","assets/useOpenInteractionType.js","assets/createBaseUIEventDetails.js","assets/addEventListener.js","assets/detail-row.js","assets/page-heading.js","assets/state-badge.js"])))=>i.map(i=>d[i]);
|
||||
import{n as e,t}from"./lazyRouteComponent.js";import{cn as n}from"./awsClient.js";import{g as r}from"./ec22.js";var i=e(`/_auth/ec2/(subnet)/describe-subnets/$id`)({loader:async({context:e,params:t})=>{await e.queryClient.ensureQueryData(r(t.id))},head:({params:e})=>({meta:[{title:`${e.id} | Subnet | Mulga`}]}),component:t(()=>n(()=>import(`./_id20.js`),__vite__mapDeps([0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32])),`component`)});export{i as t};
|
||||
@@ -1,2 +1,2 @@
|
||||
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/_id19.js","assets/compiler-runtime.js","assets/SignatureV4.js","assets/fromUtf8.browser.js","assets/ec2.js","assets/awsClient.js","assets/toUtf8.browser.js","assets/ec22.js","assets/DescribeInstancesCommand.js","assets/queryOptions.js","assets/QueryClientProvider.js","assets/error-banner.js","assets/mutation.js","assets/alert-dialog.js","assets/button.js","assets/dist.js","assets/DialogTitle.js","assets/useOpenInteractionType.js","assets/createBaseUIEventDetails.js","assets/useTransitionStatus.js","assets/useStore.js","assets/input.js","assets/separator.js","assets/useSuspenseQuery.js","assets/useBaseQuery.js","assets/query.js","assets/link.js","assets/useNavigate.js","assets/back-link.js","assets/createLucideIcon.js","assets/copy.js","assets/trash-2.js","assets/delete-confirmation-dialog.js","assets/detail-row.js","assets/page-heading.js","assets/state-badge.js","assets/field.js"])))=>i.map(i=>d[i]);
|
||||
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/_id19.js","assets/compiler-runtime.js","assets/SignatureV4.js","assets/fromUtf8.browser.js","assets/ec2.js","assets/awsClient.js","assets/toUtf8.browser.js","assets/ec22.js","assets/DescribeInstancesCommand.js","assets/queryOptions.js","assets/QueryClientProvider.js","assets/error-banner.js","assets/mutation.js","assets/alert-dialog.js","assets/button.js","assets/dist.js","assets/DialogTitle.js","assets/useOpenInteractionType.js","assets/createBaseUIEventDetails.js","assets/addEventListener.js","assets/useStore.js","assets/input.js","assets/separator.js","assets/useSuspenseQuery.js","assets/useBaseQuery.js","assets/query.js","assets/link.js","assets/useNavigate.js","assets/back-link.js","assets/createLucideIcon.js","assets/copy.js","assets/trash-2.js","assets/delete-confirmation-dialog.js","assets/detail-row.js","assets/page-heading.js","assets/state-badge.js","assets/field.js"])))=>i.map(i=>d[i]);
|
||||
import{n as e,t}from"./lazyRouteComponent.js";import{cn as n}from"./awsClient.js";import{d as r,m as i}from"./ec22.js";var a=e(`/_auth/ec2/(snapshots)/describe-snapshots/$id`)({loader:async({context:e,params:t})=>{await Promise.all([e.queryClient.ensureQueryData(i(t.id)),e.queryClient.ensureQueryData(r)])},head:({params:e})=>({meta:[{title:`${e.id} | EC2 | Mulga`}]}),component:t(()=>n(()=>import(`./_id19.js`),__vite__mapDeps([0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36])),`component`)});export{a as t};
|
||||
@@ -1,2 +1,2 @@
|
||||
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/_id17.js","assets/compiler-runtime.js","assets/ec2.js","assets/awsClient.js","assets/SignatureV4.js","assets/fromUtf8.browser.js","assets/toUtf8.browser.js","assets/ec22.js","assets/DescribeInstancesCommand.js","assets/queryOptions.js","assets/QueryClientProvider.js","assets/error-banner.js","assets/mutation.js","assets/button.js","assets/dist.js","assets/useSuspenseQuery.js","assets/useBaseQuery.js","assets/query.js","assets/link.js","assets/useStore.js","assets/useNavigate.js","assets/back-link.js","assets/createLucideIcon.js","assets/trash-2.js","assets/delete-confirmation-dialog.js","assets/alert-dialog.js","assets/DialogTitle.js","assets/useOpenInteractionType.js","assets/createBaseUIEventDetails.js","assets/useTransitionStatus.js","assets/detail-row.js","assets/page-heading.js","assets/state-badge.js"])))=>i.map(i=>d[i]);
|
||||
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/_id17.js","assets/compiler-runtime.js","assets/ec2.js","assets/awsClient.js","assets/SignatureV4.js","assets/fromUtf8.browser.js","assets/toUtf8.browser.js","assets/ec22.js","assets/DescribeInstancesCommand.js","assets/queryOptions.js","assets/QueryClientProvider.js","assets/error-banner.js","assets/mutation.js","assets/button.js","assets/dist.js","assets/useSuspenseQuery.js","assets/useBaseQuery.js","assets/query.js","assets/link.js","assets/useStore.js","assets/useNavigate.js","assets/back-link.js","assets/createLucideIcon.js","assets/trash-2.js","assets/delete-confirmation-dialog.js","assets/alert-dialog.js","assets/DialogTitle.js","assets/useOpenInteractionType.js","assets/createBaseUIEventDetails.js","assets/addEventListener.js","assets/detail-row.js","assets/page-heading.js","assets/state-badge.js"])))=>i.map(i=>d[i]);
|
||||
import{n as e,t}from"./lazyRouteComponent.js";import{cn as n}from"./awsClient.js";import{l as r,o as i}from"./ec22.js";var a=e(`/_auth/ec2/(placement-groups)/describe-placement-groups/$id`)({loader:async({context:e,params:t})=>{await Promise.all([e.queryClient.ensureQueryData(r(t.id)),e.queryClient.ensureQueryData(i)])},head:({params:e})=>({meta:[{title:`${e.id} | EC2 | Mulga`}]}),component:t(()=>n(()=>import(`./_id17.js`),__vite__mapDeps([0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32])),`component`)});export{a as t};
|
||||
@@ -1,2 +1,2 @@
|
||||
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/_id16.js","assets/compiler-runtime.js","assets/SignatureV4.js","assets/fromUtf8.browser.js","assets/ec22.js","assets/awsClient.js","assets/toUtf8.browser.js","assets/DescribeInstancesCommand.js","assets/queryOptions.js","assets/elbv2.js","assets/QueryClientProvider.js","assets/error-banner.js","assets/mutation.js","assets/elbv22.js","assets/alert-dialog.js","assets/button.js","assets/dist.js","assets/DialogTitle.js","assets/useOpenInteractionType.js","assets/createBaseUIEventDetails.js","assets/useTransitionStatus.js","assets/useStore.js","assets/tabs.js","assets/select.js","assets/getDisabledMountTransitionStyles.js","assets/separator.js","assets/createLucideIcon.js","assets/check.js","assets/chevron-down.js","assets/input.js","assets/field.js","assets/zod.js","assets/useSuspenseQuery.js","assets/useBaseQuery.js","assets/query.js","assets/useNavigate.js","assets/back-link.js","assets/link.js","assets/trash-2.js","assets/delete-confirmation-dialog.js","assets/detail-row.js","assets/page-heading.js","assets/state-badge.js","assets/elbv23.js"])))=>i.map(i=>d[i]);
|
||||
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/_id16.js","assets/compiler-runtime.js","assets/SignatureV4.js","assets/fromUtf8.browser.js","assets/ec22.js","assets/awsClient.js","assets/toUtf8.browser.js","assets/DescribeInstancesCommand.js","assets/queryOptions.js","assets/elbv2.js","assets/QueryClientProvider.js","assets/error-banner.js","assets/mutation.js","assets/elbv22.js","assets/alert-dialog.js","assets/button.js","assets/dist.js","assets/DialogTitle.js","assets/useOpenInteractionType.js","assets/createBaseUIEventDetails.js","assets/addEventListener.js","assets/useStore.js","assets/tabs.js","assets/select.js","assets/usePositioner.js","assets/separator.js","assets/createLucideIcon.js","assets/check.js","assets/chevron-down.js","assets/input.js","assets/field.js","assets/zod.js","assets/useSuspenseQuery.js","assets/useBaseQuery.js","assets/query.js","assets/useNavigate.js","assets/back-link.js","assets/link.js","assets/trash-2.js","assets/delete-confirmation-dialog.js","assets/detail-row.js","assets/page-heading.js","assets/state-badge.js","assets/elbv23.js"])))=>i.map(i=>d[i]);
|
||||
import{n as e,t}from"./lazyRouteComponent.js";import{cn as n}from"./awsClient.js";import{_ as r}from"./ec22.js";import{a as i,c as a,n as o,r as s,t as c}from"./elbv22.js";var l=e(`/_auth/ec2/(load-balancers)/describe-load-balancers/$id`)({loader:async({context:e,params:t})=>{let n=decodeURIComponent(t.id);await Promise.all([e.queryClient.ensureQueryData(s(n)),e.queryClient.ensureQueryData(c(n)),e.queryClient.ensureQueryData(o(n)),e.queryClient.ensureQueryData(i([n])),e.queryClient.ensureQueryData(a),e.queryClient.ensureQueryData(r)])},head:({params:e})=>({meta:[{title:`${decodeURIComponent(e.id)} | Load Balancer | Mulga`}]}),component:t(()=>n(()=>import(`./_id16.js`),__vite__mapDeps([0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43])),`component`)});export{l as t};
|
||||
@@ -1,2 +1,2 @@
|
||||
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/_policyArn2.js","assets/compiler-runtime.js","assets/SignatureV4.js","assets/fromUtf8.browser.js","assets/iam.js","assets/awsClient.js","assets/toUtf8.browser.js","assets/QueryClientProvider.js","assets/error-banner.js","assets/mutation.js","assets/iam2.js","assets/queryOptions.js","assets/button.js","assets/dist.js","assets/useSuspenseQuery.js","assets/useBaseQuery.js","assets/query.js","assets/useNavigate.js","assets/useStore.js","assets/back-link.js","assets/link.js","assets/createLucideIcon.js","assets/trash-2.js","assets/delete-confirmation-dialog.js","assets/alert-dialog.js","assets/DialogTitle.js","assets/useOpenInteractionType.js","assets/createBaseUIEventDetails.js","assets/useTransitionStatus.js","assets/detail-row.js","assets/page-heading.js"])))=>i.map(i=>d[i]);
|
||||
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/_policyArn2.js","assets/compiler-runtime.js","assets/SignatureV4.js","assets/fromUtf8.browser.js","assets/iam.js","assets/awsClient.js","assets/toUtf8.browser.js","assets/QueryClientProvider.js","assets/error-banner.js","assets/mutation.js","assets/iam2.js","assets/queryOptions.js","assets/button.js","assets/dist.js","assets/useSuspenseQuery.js","assets/useBaseQuery.js","assets/query.js","assets/useNavigate.js","assets/useStore.js","assets/back-link.js","assets/link.js","assets/createLucideIcon.js","assets/trash-2.js","assets/delete-confirmation-dialog.js","assets/alert-dialog.js","assets/DialogTitle.js","assets/useOpenInteractionType.js","assets/createBaseUIEventDetails.js","assets/addEventListener.js","assets/detail-row.js","assets/page-heading.js"])))=>i.map(i=>d[i]);
|
||||
import{n as e,t}from"./lazyRouteComponent.js";import{cn as n}from"./awsClient.js";import{a as r,i}from"./iam2.js";var a=e(`/_auth/iam/(policies)/list-policies/$policyArn`)({loader:async({context:e,params:t})=>{let n=decodeURIComponent(t.policyArn),a=await e.queryClient.ensureQueryData(i(n)),o=a.Policy?.DefaultVersionId;return o&&await e.queryClient.ensureQueryData(r(n,o)),a},head:({loaderData:e})=>({meta:[{title:`${e?.Policy?.PolicyName??`Policy`} | IAM | Mulga`}]}),component:t(()=>n(()=>import(`./_policyArn2.js`),__vite__mapDeps([0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30])),`component`)});export{a as t};
|
||||
@@ -1,2 +1,2 @@
|
||||
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/_userName2.js","assets/compiler-runtime.js","assets/SignatureV4.js","assets/fromUtf8.browser.js","assets/iam.js","assets/awsClient.js","assets/toUtf8.browser.js","assets/QueryClientProvider.js","assets/error-banner.js","assets/mutation.js","assets/iam2.js","assets/queryOptions.js","assets/alert-dialog.js","assets/button.js","assets/dist.js","assets/DialogTitle.js","assets/useOpenInteractionType.js","assets/createBaseUIEventDetails.js","assets/useTransitionStatus.js","assets/useStore.js","assets/useSuspenseQuery.js","assets/useBaseQuery.js","assets/query.js","assets/useNavigate.js","assets/back-link.js","assets/link.js","assets/createLucideIcon.js","assets/check.js","assets/trash-2.js","assets/triangle-alert.js","assets/delete-confirmation-dialog.js","assets/detail-row.js","assets/page-heading.js","assets/state-badge.js","assets/use-copy-to-clipboard.js"])))=>i.map(i=>d[i]);
|
||||
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/_userName2.js","assets/compiler-runtime.js","assets/SignatureV4.js","assets/fromUtf8.browser.js","assets/iam.js","assets/awsClient.js","assets/toUtf8.browser.js","assets/QueryClientProvider.js","assets/error-banner.js","assets/mutation.js","assets/iam2.js","assets/queryOptions.js","assets/alert-dialog.js","assets/button.js","assets/dist.js","assets/DialogTitle.js","assets/useOpenInteractionType.js","assets/createBaseUIEventDetails.js","assets/addEventListener.js","assets/useStore.js","assets/useSuspenseQuery.js","assets/useBaseQuery.js","assets/query.js","assets/useNavigate.js","assets/back-link.js","assets/link.js","assets/createLucideIcon.js","assets/check.js","assets/trash-2.js","assets/triangle-alert.js","assets/delete-confirmation-dialog.js","assets/detail-row.js","assets/page-heading.js","assets/state-badge.js","assets/use-copy-to-clipboard.js"])))=>i.map(i=>d[i]);
|
||||
import{n as e,t}from"./lazyRouteComponent.js";import{cn as n}from"./awsClient.js";import{n as r,o as i,r as a,t as o}from"./iam2.js";var s=e(`/_auth/iam/(users)/list-users/$userName`)({loader:async({context:e,params:t})=>{await Promise.all([e.queryClient.ensureQueryData(i(t.userName)),e.queryClient.ensureQueryData(o(t.userName)),e.queryClient.ensureQueryData(r(t.userName)),e.queryClient.ensureQueryData(a)])},head:({params:e})=>({meta:[{title:`${e.userName} | IAM | Mulga`}]}),component:t(()=>n(()=>import(`./_userName2.js`),__vite__mapDeps([0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34])),`component`)});export{s as t};
|
||||
@@ -0,0 +1 @@
|
||||
import{a as e,r as t}from"./compiler-runtime.js";import{hn as n}from"./awsClient.js";import{p as r}from"./dist.js";import{c as i,o as a}from"./button.js";var o=e(n()),s=e(t()),c=[];function l(e){s.useEffect(e,c)}var u=null;globalThis.requestAnimationFrame;var d=new class{callbacks=[];callbacksCount=0;nextId=1;startId=1;isScheduled=!1;tick=e=>{this.isScheduled=!1;let t=this.callbacks,n=this.callbacksCount;if(this.callbacks=[],this.callbacksCount=0,this.startId=this.nextId,n>0)for(let n=0;n<t.length;n+=1)t[n]?.(e)};request(e){let t=this.nextId;return this.nextId+=1,this.callbacks.push(e),this.callbacksCount+=1,this.isScheduled||=(requestAnimationFrame(this.tick),!0),t}cancel(e){let t=e-this.startId;t<0||t>=this.callbacks.length||(this.callbacks[t]=null,--this.callbacksCount)}},f=class e{static create(){return new e}static request(e){return d.request(e)}static cancel(e){return d.cancel(e)}currentId=u;request(e){this.cancel(),this.currentId=d.request(()=>{this.currentId=u,e()})}cancel=()=>{this.currentId!==u&&(d.cancel(this.currentId),this.currentId=u)};disposeEffect=()=>this.cancel};function p(){let e=r(f.create).current;return l(e.disposeEffect),e}function m(e){return e==null?e:`current`in e?e.current:e}var h=function(e){return e.startingStyle=`data-starting-style`,e.endingStyle=`data-ending-style`,e}({}),g={[h.startingStyle]:``},_={[h.endingStyle]:``},v={transitionStatus(e){return e===`starting`?g:e===`ending`?_:null}};function y(e,t=!1,n=!0){let r=p();return i((i,a=null)=>{r.cancel();let s=m(e);if(s==null)return;let c=s,l=()=>{o.flushSync(i)};if(typeof c.getAnimations!=`function`||globalThis.BASE_UI_ANIMATIONS_DISABLED){i();return}function u(){Promise.all(c.getAnimations().map(e=>e.finished)).then(()=>{a?.aborted||l()}).catch(()=>{if(n){a?.aborted||l();return}let e=c.getAnimations();!a?.aborted&&e.length>0&&e.some(e=>e.pending||e.playState!==`finished`)&&u()})}if(t){let e=h.startingStyle;if(!c.hasAttribute(e)){r.request(u);return}let t=new MutationObserver(()=>{c.hasAttribute(e)||(t.disconnect(),u())});t.observe(c,{attributes:!0,attributeFilter:[e]}),a?.addEventListener(`abort`,()=>t.disconnect(),{once:!0});return}r.request(u)})}function b(e){let{enabled:t=!0,open:n,ref:r,onComplete:a}=e,o=i(a),c=y(r,n,!1);s.useEffect(()=>{if(!t)return;let e=new AbortController;return c(o,e.signal),()=>{e.abort()}},[t,n,o,c])}function x(e,t=!1,n=!1){let[r,i]=s.useState(e&&t?`idle`:void 0),[o,c]=s.useState(e);return e&&!o&&(c(!0),i(`starting`)),!e&&o&&r!==`ending`&&!n&&i(`ending`),!e&&!o&&r===`ending`&&i(void 0),a(()=>{if(!e&&o&&r!==`ending`&&n){let e=f.request(()=>{i(`ending`)});return()=>{f.cancel(e)}}},[e,o,r,n]),a(()=>{if(!e||t)return;let n=f.request(()=>{i(void 0)});return()=>{f.cancel(n)}},[t,e]),a(()=>{if(!e||!t)return;e&&o&&r!==`idle`&&i(`starting`);let n=f.request(()=>{i(`idle`)});return()=>{f.cancel(n)}},[t,e,o,r]),{mounted:o,setMounted:c,transitionStatus:r}}function S(e,t,n,r){return e.addEventListener(t,n,r),()=>{e.removeEventListener(t,n,r)}}export{h as a,f as c,y as i,p as l,x as n,v as o,b as r,m as s,S as t,l as u};
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1,2 +1,2 @@
|
||||
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/create-snapshot2.js","assets/compiler-runtime.js","assets/ec2.js","assets/awsClient.js","assets/SignatureV4.js","assets/fromUtf8.browser.js","assets/toUtf8.browser.js","assets/ec22.js","assets/DescribeInstancesCommand.js","assets/queryOptions.js","assets/QueryClientProvider.js","assets/error-banner.js","assets/mutation.js","assets/select.js","assets/button.js","assets/dist.js","assets/useOpenInteractionType.js","assets/createBaseUIEventDetails.js","assets/useTransitionStatus.js","assets/useStore.js","assets/getDisabledMountTransitionStyles.js","assets/separator.js","assets/createLucideIcon.js","assets/check.js","assets/chevron-down.js","assets/zod.js","assets/useSuspenseQuery.js","assets/useBaseQuery.js","assets/query.js","assets/useNavigate.js","assets/back-link.js","assets/link.js","assets/cli-command-panel.js","assets/copy.js","assets/use-copy-to-clipboard.js","assets/form-actions.js","assets/page-heading.js","assets/field.js","assets/textarea.js","assets/ec23.js"])))=>i.map(i=>d[i]);
|
||||
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/create-snapshot2.js","assets/compiler-runtime.js","assets/ec2.js","assets/awsClient.js","assets/SignatureV4.js","assets/fromUtf8.browser.js","assets/toUtf8.browser.js","assets/ec22.js","assets/DescribeInstancesCommand.js","assets/queryOptions.js","assets/QueryClientProvider.js","assets/error-banner.js","assets/mutation.js","assets/select.js","assets/button.js","assets/dist.js","assets/useOpenInteractionType.js","assets/createBaseUIEventDetails.js","assets/addEventListener.js","assets/useStore.js","assets/usePositioner.js","assets/separator.js","assets/createLucideIcon.js","assets/check.js","assets/chevron-down.js","assets/zod.js","assets/useSuspenseQuery.js","assets/useBaseQuery.js","assets/query.js","assets/useNavigate.js","assets/back-link.js","assets/link.js","assets/cli-command-panel.js","assets/copy.js","assets/use-copy-to-clipboard.js","assets/form-actions.js","assets/page-heading.js","assets/field.js","assets/textarea.js","assets/ec23.js"])))=>i.map(i=>d[i]);
|
||||
import{n as e,t}from"./lazyRouteComponent.js";import{cn as n}from"./awsClient.js";import{y as r}from"./ec22.js";var i=e(`/_auth/ec2/(snapshots)/create-snapshot`)({validateSearch:e=>({volumeId:typeof e.volumeId==`string`?e.volumeId:void 0}),loader:async({context:e})=>{await e.queryClient.ensureQueryData(r)},head:()=>({meta:[{title:`Create Snapshot | EC2 | Mulga`}]}),component:t(()=>n(()=>import(`./create-snapshot2.js`),__vite__mapDeps([0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39])),`component`)});export{i as t};
|
||||
+1
-1
@@ -1 +1 @@
|
||||
import{a as e,r as t}from"./compiler-runtime.js";import{l as n}from"./dist.js";import{b as r,s as i,w as a,y as o}from"./button.js";var s=e(t()),c=0;function l(e,t=`mui`){let[n,r]=s.useState(e),i=e||n;return s.useEffect(()=>{n??(c+=1,r(`${t}-${c}`))},[n,t]),i}var u=i.useId;function d(e,t){if(u!==void 0){let n=u();return e??(t?`${t}-${n}`:n)}return l(e,t)}function f(e){return d(e,`base-ui`)}function p(e){return e?.ownerDocument||document}var m=typeof navigator<`u`,h=w(),g=E(),_=T(),v=typeof CSS>`u`||!CSS.supports?!1:CSS.supports(`-webkit-backdrop-filter:none`),y=h.platform===`MacIntel`&&h.maxTouchPoints>1?!0:/iP(hone|ad|od)|iOS/.test(h.platform);m&&/firefox/i.test(_);var b=m&&/apple/i.test(navigator.vendor);m&&/Edg/i.test(_);var x=m&&/android/i.test(g)||/android/i.test(_),S=m&&g.toLowerCase().startsWith(`mac`)&&!navigator.maxTouchPoints,C=_.includes(`jsdom/`);function w(){if(!m)return{platform:``,maxTouchPoints:-1};let e=navigator.userAgentData;return e?.platform?{platform:e.platform,maxTouchPoints:navigator.maxTouchPoints}:{platform:navigator.platform??``,maxTouchPoints:navigator.maxTouchPoints??-1}}function T(){if(!m)return``;let e=navigator.userAgentData;return e&&Array.isArray(e.brands)?e.brands.map(({brand:e,version:t})=>`${e}/${t}`).join(` `):navigator.userAgent}function E(){if(!m)return``;let e=navigator.userAgentData;return e?.platform?e.platform:navigator.platform??``}var D=`data-base-ui-focusable`,O=`active`,k=`selected`,A=`input:not([type='hidden']):not([disabled]),[contenteditable]:not([contenteditable='false']),textarea:not([disabled])`,j=`ArrowLeft`,M=`ArrowRight`,N=`ArrowUp`,P=`ArrowDown`;function F(e){let t=e.activeElement;for(;t?.shadowRoot?.activeElement!=null;)t=t.shadowRoot.activeElement;return t}function I(e,t){if(!e||!t)return!1;let n=t.getRootNode?.();if(e.contains(t))return!0;if(n&&a(n)){let n=t;for(;n;){if(e===n)return!0;n=n.parentNode||n.host}}return!1}function L(e,t){if(!o(e))return!1;let n=e;if(t.hasElement(n))return!n.hasAttribute(`data-trigger-disabled`);for(let[,e]of t.entries())if(I(e,n))return!e.hasAttribute(`data-trigger-disabled`);return!1}function R(e){return`composedPath`in e?e.composedPath()[0]:e.target}function ee(e,t){if(t==null)return!1;if(`composedPath`in e)return e.composedPath().includes(t);let n=e;return n.target!=null&&t.contains(n.target)}function z(e){return e.matches(`html,body`)}function B(e){return r(e)&&e.matches(`input:not([type='hidden']):not([disabled]),[contenteditable]:not([contenteditable='false']),textarea:not([disabled])`)}function V(e){return e?e.getAttribute(`role`)===`combobox`&&B(e):!1}function H(e){if(!e||C)return!0;try{return e.matches(`:focus-visible`)}catch{return!0}}function U(e){return e?e.hasAttribute(`data-base-ui-focusable`)?e:e.querySelector(`[data-base-ui-focusable]`)||e:null}var W=`none`,G=`trigger-press`,K=`trigger-hover`,q=`trigger-focus`,J=`outside-press`,Y=`item-press`,X=`close-press`,Z=`focus-out`,Q=`escape-key`,$=`list-navigation`,te=`cancel-open`,ne=`disabled`,re=`imperative-action`,ie=`window-resize`;function ae(e,t,r,i){let a=!1,o=!1,s=i??n;return{reason:e,event:t??new Event(`base-ui`),cancel(){a=!0},allowPropagation(){o=!0},get isCanceled(){return a},get isPropagationAllowed(){return o},trigger:r,...s}}export{N as A,p as B,V as C,P as D,O as E,y as F,d as H,C as I,S as L,k as M,A as N,j as O,x as P,b as R,L as S,H as T,f as V,I as _,Q as a,ee as b,Y as c,J as d,q as f,F as g,ie as h,ne as i,D as j,M as k,$ as l,G as m,te as n,Z as o,K as p,X as r,re as s,ae as t,W as u,U as v,B as w,z as x,R as y,v as z};
|
||||
import{a as e,r as t}from"./compiler-runtime.js";import{l as n}from"./dist.js";import{s as r,w as i}from"./button.js";var a=e(t()),o=0;function s(e,t=`mui`){let[n,r]=a.useState(e),i=e||n;return a.useEffect(()=>{n??(o+=1,r(`${t}-${o}`))},[n,t]),i}var c=r.useId;function l(e,t){if(c!==void 0){let n=c();return e??(t?`${t}-${n}`:n)}return s(e,t)}function u(e){return l(e,`base-ui`)}function d(e){return e?.ownerDocument||document}function f(e){let t=e.activeElement;for(;t?.shadowRoot?.activeElement!=null;)t=t.shadowRoot.activeElement;return t}function p(e,t){if(!e||!t)return!1;let n=t.getRootNode?.();if(e.contains(t))return!0;if(n&&i(n)){let n=t;for(;n;){if(e===n)return!0;n=n.parentNode||n.host}}return!1}function m(e){return`composedPath`in e?e.composedPath()[0]:e.target}var h=`none`,g=`trigger-press`,_=`trigger-hover`,v=`trigger-focus`,y=`outside-press`,b=`item-press`,x=`close-press`,S=`focus-out`,C=`escape-key`,w=`list-navigation`,T=`cancel-open`,E=`disabled`,D=`imperative-action`,O=`window-resize`;function k(e,t,r,i){let a=!1,o=!1,s=i??n;return{reason:e,event:t??new Event(`base-ui`),cancel(){a=!0},allowPropagation(){o=!0},get isCanceled(){return a},get isPropagationAllowed(){return o},trigger:r,...s}}export{p as _,C as a,u as b,b as c,y as d,v as f,f as g,O as h,E as i,w as l,g as m,T as n,S as o,_ as p,x as r,D as s,k as t,h as u,m as v,l as x,d as y};
|
||||
File diff suppressed because one or more lines are too long
-1
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1 +1 @@
|
||||
import{a as e,n as t,r as n,t as r}from"./compiler-runtime.js";import{n as i}from"./dist.js";import{I as a}from"./SignatureV4.js";import{o}from"./button.js";import{a as s,c,i as l,n as u,r as d,s as f}from"./separator.js";import{B as p,g as m,t as h,u as g}from"./createBaseUIEventDetails.js";var _=e(n()),v=_.forwardRef(function(e,t){let{render:n,className:r,id:a,name:v,value:y,disabled:b=!1,onValueChange:x,defaultValue:S,autoFocus:C=!1,...w}=e,{state:T,name:E,disabled:D,setTouched:O,setDirty:k,validityData:A,setFocused:j,setFilled:M,validationMode:N,validation:P}=f(),F=D||b,I=E??v,L={...T,disabled:F},{labelId:R}=s(),z=d({id:a});o(()=>{let e=y!=null;P.inputRef.current?.value||e&&y!==``?M(!0):e&&y===``&&M(!1)},[P.inputRef,M,y]);let B=_.useRef(null);o(()=>{C&&B.current===m(p(B.current))&&j(!0)},[C,j]);let[V]=l({controlled:y,default:S,name:`FieldControl`,state:`value`}),H=y!==void 0,U=H?V:void 0;return u({id:z,name:I,commit:P.commit,value:U,getValue:()=>P.inputRef.current?.value,controlRef:P.inputRef}),i(`input`,e,{ref:[t,B],state:L,props:[{id:z,disabled:F,name:I,ref:P.inputRef,"aria-labelledby":R,autoFocus:C,...H?{value:U}:{defaultValue:S},onChange(e){let t=e.currentTarget.value;x?.(t,h(g,e.nativeEvent)),k(t!==A.initialValue),M(t!==``)},onFocus(){j(!0)},onBlur(e){O(!0),j(!1),N===`onBlur`&&P.commit(e.currentTarget.value)},onKeyDown(e){e.currentTarget.tagName===`INPUT`&&e.key===`Enter`&&(O(!0),P.commit(e.currentTarget.value))}},P.getInputValidationProps(),w],stateAttributesMapping:c})}),y=t(),b=_.forwardRef(function(e,t){return(0,y.jsx)(v,{ref:t,...e})}),x=r();function S(e){let t=(0,x.c)(10),n,r,i;t[0]===e?(n=t[1],r=t[2],i=t[3]):({className:n,type:i,...r}=e,t[0]=e,t[1]=n,t[2]=r,t[3]=i);let o;t[4]===n?o=t[5]:(o=a(`h-7 w-full min-w-0 rounded-md border border-input bg-input/20 px-2 py-0.5 text-sm transition-colors outline-none file:inline-flex file:h-6 file:border-0 file:bg-transparent file:text-xs/relaxed file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-2 focus-visible:ring-ring/30 disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-2 aria-invalid:ring-destructive/20 md:text-xs/relaxed dark:bg-input/30 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40`,n),t[4]=n,t[5]=o);let s;return t[6]!==r||t[7]!==o||t[8]!==i?(s=(0,y.jsx)(b,{className:o,"data-slot":`input`,type:i,...r}),t[6]=r,t[7]=o,t[8]=i,t[9]=s):s=t[9],s}export{S as t};
|
||||
import{a as e,n as t,r as n,t as r}from"./compiler-runtime.js";import{n as i}from"./dist.js";import{I as a}from"./SignatureV4.js";import{c as o,o as s}from"./button.js";import{a as c,i as l,n as u,o as d,r as f,s as p}from"./separator.js";import{g as m,t as h,u as g,y as _}from"./createBaseUIEventDetails.js";var v=e(n()),y=v.forwardRef(function(e,t){let{render:n,className:r,id:a,name:y,value:b,disabled:x=!1,onValueChange:S,defaultValue:C,autoFocus:w=!1,style:T,...E}=e,{state:D,name:O,disabled:k,setTouched:A,setDirty:j,validityData:M,setFocused:N,setFilled:P,validationMode:F,validation:I}=d(),L=k||x,R=O??y,z={...D,disabled:L},{labelId:B}=c(),V=u({id:a});s(()=>{let e=b!=null;I.inputRef.current?.value||e&&b!==``?P(!0):e&&b===``&&P(!1)},[I.inputRef,P,b]);let H=v.useRef(null);s(()=>{w&&H.current===m(_(H.current))&&N(!0)},[w,N]);let[U]=l({controlled:b,default:C,name:`FieldControl`,state:`value`}),W=b!==void 0,G=W?U:void 0,K=o(()=>I.inputRef.current?.value);return f(I.inputRef,{id:V,value:G,getValue:K}),i(`input`,e,{ref:[t,H],state:z,props:[{id:V,disabled:L,name:R,ref:I.inputRef,"aria-labelledby":B,autoFocus:w,...W?{value:G}:{defaultValue:C},onChange(e){let t=e.currentTarget.value;S?.(t,h(g,e.nativeEvent)),j(t!==M.initialValue),P(t!==``)},onFocus(){N(!0)},onBlur(e){A(!0),N(!1),F===`onBlur`&&I.commit(e.currentTarget.value)},onKeyDown(e){e.currentTarget.tagName===`INPUT`&&e.key===`Enter`&&(A(!0),I.commit(e.currentTarget.value))}},I.getInputValidationProps(),E],stateAttributesMapping:p})}),b=t(),x=v.forwardRef(function(e,t){return(0,b.jsx)(y,{ref:t,...e})}),S=r();function C(e){let t=(0,S.c)(10),n,r,i;t[0]===e?(n=t[1],r=t[2],i=t[3]):({className:n,type:i,...r}=e,t[0]=e,t[1]=n,t[2]=r,t[3]=i);let o;t[4]===n?o=t[5]:(o=a(`h-7 w-full min-w-0 rounded-md border border-input bg-input/20 px-2 py-0.5 text-sm transition-colors outline-none file:inline-flex file:h-6 file:border-0 file:bg-transparent file:text-xs/relaxed file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-2 focus-visible:ring-ring/30 disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-2 aria-invalid:ring-destructive/20 md:text-xs/relaxed dark:bg-input/30 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40`,n),t[4]=n,t[5]=o);let s;return t[6]!==r||t[7]!==o||t[8]!==i?(s=(0,b.jsx)(x,{className:o,"data-slot":`input`,type:i,...r}),t[6]=r,t[7]=o,t[8]=i,t[9]=s):s=t[9],s}export{C as t};
|
||||
@@ -1 +1 @@
|
||||
import{a as e,n as t,r as n}from"./compiler-runtime.js";import{B as r,P as i,_ as a,f as o,g as s,i as c,t as l,w as u,z as d}from"./useStore.js";import{n as f,r as p,t as m}from"./matchContext.js";import{n as h}from"./redirect.js";import{t as g}from"./link.js";import{t as _}from"./useNavigate.js";var v=class{get to(){return this._to}get id(){return this._id}get path(){return this._path}get fullPath(){return this._fullPath}constructor(e){if(this.init=e=>{this.originalIndex=e.originalIndex;let t=this.options,n=!t?.path&&!t?.id;this.parentRoute=this.options.getParentRoute?.(),n?this._path=p:this.parentRoute||u();let r=n?p:t?.path;r&&r!==`/`&&(r=s(r));let i=t?.id||r,c=n?p:o([this.parentRoute.id===`__root__`?``:this.parentRoute.id,i]);r===`__root__`&&(r=`/`),c!==`__root__`&&(c=o([`/`,c]));let l=c===`__root__`?`/`:o([this.parentRoute.fullPath,r]);this._path=r,this._id=c,this._fullPath=l,this._to=a(l)},this.addChildren=e=>this._addFileChildren(e),this._addFileChildren=e=>(Array.isArray(e)&&(this.children=e),typeof e==`object`&&e&&(this.children=Object.values(e)),this),this._addFileTypes=()=>this,this.updateLoader=e=>(Object.assign(this.options,e),this),this.update=e=>(Object.assign(this.options,e),this),this.lazy=e=>(this.lazyFn=e,this),this.redirect=e=>h({from:this.fullPath,...e}),this.options=e||{},this.isRoot=!e?.getParentRoute,e?.id&&e?.path)throw Error(`Route cannot have both an 'id' and a 'path' option.`)}},y=class extends v{constructor(e){super(e)}},b=e(n(),1),x={get:()=>void 0,subscribe:()=>({unsubscribe:()=>{}})};function S(e){let t=c(),n=b.useContext(e.from?m:f),r=e.from??n,i=r?e.from?t.stores.getRouteMatchStore(r):t.stores.matchStores.get(r):void 0,a=b.useRef(void 0);return l(i??x,n=>{if((e.shouldThrow??!0)&&!n&&u(),n===void 0)return;let r=e.select?e.select(n):n;if(e.structuralSharing??t.options.defaultStructuralSharing){let e=d(a.current,r);return a.current=e,e}return r})}function C(e){return S({from:e.from,strict:e.strict,structuralSharing:e.structuralSharing,select:t=>e.select?e.select(t.loaderData):t.loaderData})}function w(e){let{select:t,...n}=e;return S({...n,select:e=>t?t(e.loaderDeps):e.loaderDeps})}function T(e){return S({from:e.from,shouldThrow:e.shouldThrow,structuralSharing:e.structuralSharing,strict:e.strict,select:t=>{let n=e.strict===!1?t.params:t._strictParams;return e.select?e.select(n):n}})}function E(e){return S({from:e.from,strict:e.strict,shouldThrow:e.shouldThrow,structuralSharing:e.structuralSharing,select:t=>e.select?e.select(t.search):t.search})}function D(e){return S({...e,select:t=>e.select?e.select(t.context):t.context})}var O=t(),k=class extends v{constructor(e){super(e),this.useMatch=e=>S({select:e?.select,from:this.id,structuralSharing:e?.structuralSharing}),this.useRouteContext=e=>D({...e,from:this.id}),this.useSearch=e=>E({select:e?.select,structuralSharing:e?.structuralSharing,from:this.id}),this.useParams=e=>T({select:e?.select,structuralSharing:e?.structuralSharing,from:this.id}),this.useLoaderDeps=e=>w({...e,from:this.id}),this.useLoaderData=e=>C({...e,from:this.id}),this.useNavigate=()=>_({from:this.fullPath}),this.Link=b.forwardRef((e,t)=>(0,O.jsx)(g,{ref:t,from:this.fullPath,...e}))}};function A(e){return new k(e)}function j(){return e=>N(e)}var M=class extends y{constructor(e){super(e),this.useMatch=e=>S({select:e?.select,from:this.id,structuralSharing:e?.structuralSharing}),this.useRouteContext=e=>D({...e,from:this.id}),this.useSearch=e=>E({select:e?.select,structuralSharing:e?.structuralSharing,from:this.id}),this.useParams=e=>T({select:e?.select,structuralSharing:e?.structuralSharing,from:this.id}),this.useLoaderDeps=e=>w({...e,from:this.id}),this.useLoaderData=e=>C({...e,from:this.id}),this.useNavigate=()=>_({from:this.fullPath}),this.Link=b.forwardRef((e,t)=>(0,O.jsx)(g,{ref:t,from:this.fullPath,...e}))}};function N(e){return new M(e)}function P(e){return typeof e==`object`?new F(e,{silent:!0}).createRoute(e):new F(e,{silent:!0}).createRoute}var F=class{constructor(e,t){this.path=e,this.createRoute=e=>{let t=A(e);return t.isRoot=!1,t},this.silent=t?.silent}};function I(e,t){let n,a,o,s,c=()=>(n||=e().then(e=>{n=void 0,a=e[t??`default`]}).catch(e=>{if(o=e,i(o)&&o instanceof Error&&typeof window<`u`&&typeof sessionStorage<`u`){let e=`tanstack_router_reload:${o.message}`;sessionStorage.getItem(e)||(sessionStorage.setItem(e,`1`),s=!0)}}),n),l=function(e){if(s)throw window.location.reload(),new Promise(()=>{});if(o)throw o;if(!a)if(r)r(c());else throw c();return b.createElement(a,e)};return l.preload=c,l}export{P as n,j as r,I as t};
|
||||
import{a as e,n as t,r as n}from"./compiler-runtime.js";import{B as r,P as i,_ as a,f as o,g as s,i as c,t as l,w as u,z as d}from"./useStore.js";import{n as f,r as p,t as m}from"./matchContext.js";import{n as h}from"./redirect.js";import{t as g}from"./link.js";import{t as _}from"./useNavigate.js";var v=class{get to(){return this._to}get id(){return this._id}get path(){return this._path}get fullPath(){return this._fullPath}constructor(e){if(this.init=e=>{this.originalIndex=e.originalIndex;let t=this.options,n=!t?.path&&!t?.id;this.parentRoute=this.options.getParentRoute?.(),n?this._path=p:this.parentRoute||u();let r=n?p:t?.path;r&&r!==`/`&&(r=s(r));let i=t?.id||r,c=n?p:o([this.parentRoute.id===`__root__`?``:this.parentRoute.id,i]);r===`__root__`&&(r=`/`),c!==`__root__`&&(c=o([`/`,c]));let l=c===`__root__`?`/`:o([this.parentRoute.fullPath,r]);this._path=r,this._id=c,this._fullPath=l,this._to=a(l)},this.addChildren=e=>this._addFileChildren(e),this._addFileChildren=e=>(Array.isArray(e)&&(this.children=e),typeof e==`object`&&e&&(this.children=Object.values(e)),this),this._addFileTypes=()=>this,this.updateLoader=e=>(Object.assign(this.options,e),this),this.update=e=>(Object.assign(this.options,e),this),this.lazy=e=>(this.lazyFn=e,this),this.redirect=e=>h({from:this.fullPath,...e}),this.options=e||{},this.isRoot=!e?.getParentRoute,e?.id&&e?.path)throw Error(`Route cannot have both an 'id' and a 'path' option.`)}},y=class extends v{constructor(e){super(e)}},b=e(n(),1),x={get:()=>void 0,subscribe:()=>({unsubscribe:()=>{}})};function S(e){let t=c(),n=b.useContext(e.from?m:f),r=e.from??n,i=r?e.from?t.stores.getRouteMatchStore(r):t.stores.matchStores.get(r):void 0,a=b.useRef(void 0);return l(i??x,n=>{if((e.shouldThrow??!0)&&!n&&u(),n===void 0)return;let r=e.select?e.select(n):n;if(e.structuralSharing??t.options.defaultStructuralSharing){let e=d(a.current,r);return a.current=e,e}return r})}function C(e){return S({from:e.from,strict:e.strict,structuralSharing:e.structuralSharing,select:t=>e.select?e.select(t.loaderData):t.loaderData})}function w(e){let{select:t,...n}=e;return S({...n,select:e=>t?t(e.loaderDeps):e.loaderDeps})}function T(e){return S({from:e.from,shouldThrow:e.shouldThrow,structuralSharing:e.structuralSharing,strict:e.strict,select:t=>{let n=e.strict===!1?t.params:t._strictParams;return e.select?e.select(n):n}})}function E(e){return S({from:e.from,strict:e.strict,shouldThrow:e.shouldThrow,structuralSharing:e.structuralSharing,select:t=>e.select?e.select(t.search):t.search})}function D(e){return S({...e,select:t=>e.select?e.select(t.context):t.context})}var O=t(),k=class extends v{constructor(e){super(e),this.useMatch=e=>S({select:e?.select,from:this.id,structuralSharing:e?.structuralSharing}),this.useRouteContext=e=>D({...e,from:this.id}),this.useSearch=e=>E({select:e?.select,structuralSharing:e?.structuralSharing,from:this.id}),this.useParams=e=>T({select:e?.select,structuralSharing:e?.structuralSharing,from:this.id}),this.useLoaderDeps=e=>w({...e,from:this.id}),this.useLoaderData=e=>C({...e,from:this.id}),this.useNavigate=()=>_({from:this.fullPath}),this.Link=b.forwardRef((e,t)=>(0,O.jsx)(g,{ref:t,from:this.fullPath,...e}))}};function A(e){return new k(e)}function j(){return e=>N(e)}var M=class extends y{constructor(e){super(e),this.useMatch=e=>S({select:e?.select,from:this.id,structuralSharing:e?.structuralSharing}),this.useRouteContext=e=>D({...e,from:this.id}),this.useSearch=e=>E({select:e?.select,structuralSharing:e?.structuralSharing,from:this.id}),this.useParams=e=>T({select:e?.select,structuralSharing:e?.structuralSharing,from:this.id}),this.useLoaderDeps=e=>w({...e,from:this.id}),this.useLoaderData=e=>C({...e,from:this.id}),this.useNavigate=()=>_({from:this.fullPath}),this.Link=b.forwardRef((e,t)=>(0,O.jsx)(g,{ref:t,from:this.fullPath,...e}))}};function N(e){return new M(e)}function P(e){return new F(e,{silent:!0}).createRoute}var F=class{constructor(e,t){this.path=e,this.createRoute=e=>{let t=A(e);return t.isRoot=!1,t},this.silent=t?.silent}};function I(e,t){let n,a,o,s,c=()=>(n||=e().then(e=>{n=void 0,a=e[t??`default`]}).catch(e=>{if(o=e,i(o)&&o instanceof Error&&typeof window<`u`&&typeof sessionStorage<`u`){let e=`tanstack_router_reload:${o.message}`;sessionStorage.getItem(e)||(sessionStorage.setItem(e,`1`),s=!0)}}),n),l=function(e){if(s)throw window.location.reload(),new Promise(()=>{});if(o)throw o;if(!a)if(r)r(c());else throw c();return b.createElement(a,e)};return l.preload=c,l}export{P as n,j as r,I as t};
|
||||
File diff suppressed because one or more lines are too long
@@ -1 +1 @@
|
||||
import{a as e,n as t,r as n,t as r}from"./compiler-runtime.js";import{hn as i}from"./awsClient.js";import{l as a,m as o,n as s,p as c,u as l}from"./dist.js";import{I as u}from"./SignatureV4.js";import{c as d,o as f,y as p}from"./button.js";import{V as m}from"./createBaseUIEventDetails.js";var h=e(n()),g=e(i()),_=function(e){return e.disabled=`data-disabled`,e.valid=`data-valid`,e.invalid=`data-invalid`,e.touched=`data-touched`,e.dirty=`data-dirty`,e.filled=`data-filled`,e.focused=`data-focused`,e}({}),v={badInput:!1,customError:!1,patternMismatch:!1,rangeOverflow:!1,rangeUnderflow:!1,stepMismatch:!1,tooLong:!1,tooShort:!1,typeMismatch:!1,valid:null,valueMissing:!1},y={valid:null,touched:!1,dirty:!1,filled:!1,focused:!1},b={disabled:!1,...y},x={valid(e){return e===null?null:e?{[_.valid]:``}:{[_.invalid]:``}}},S=h.createContext({invalid:void 0,name:void 0,validityData:{state:v,errors:[],error:``,value:``,initialValue:null},setValidityData:l,disabled:void 0,touched:y.touched,setTouched:l,dirty:y.dirty,setDirty:l,filled:y.filled,setFilled:l,focused:y.focused,setFocused:l,validate:()=>null,validationMode:`onSubmit`,validationDebounceTime:0,shouldValidateOnChange:()=>!1,state:b,markedDirtyRef:{current:!1},validation:{getValidationProps:(e=a)=>e,getInputValidationProps:(e=a)=>e,inputRef:{current:null},commit:async()=>{}}});function C(e=!0){let t=h.useContext(S);if(t.setValidityData===l&&!e)throw Error(o(28));return t}var w=h.createContext({formRef:{current:{fields:new Map}},errors:{},clearErrors:l,validationMode:`onSubmit`,submitAttemptedRef:{current:!1}});function T(){return h.useContext(w)}var E=h.createContext({controlId:void 0,registerControlId:l,labelId:void 0,setLabelId:l,messageIds:[],setMessageIds:l,getDescriptionProps:e=>e});function D(){return h.useContext(E)}function O(e,t){return{...e,state:{...e.state,valid:!t&&e.state.valid}}}function k({controlled:e,default:t,name:n,state:r=`value`}){let{current:i}=h.useRef(e!==void 0),[a,o]=h.useState(t);return[i?e:a,h.useCallback(e=>{i||o(e)},[])]}function A(e={}){let{id:t,implicit:n=!1,controlRef:r}=e,{controlId:i,registerControlId:a}=D(),o=m(t),s=n?i:void 0,u=c(()=>Symbol(`labelable-control`)),g=h.useRef(!1),_=h.useRef(t!=null),v=d(()=>{!g.current||a===l||(g.current=!1,a(u.current,void 0))});return f(()=>{if(a===l)return;let e;if(n){let n=r?.current;e=p(n)&&n.closest(`label`)!=null?t??null:s??o}else if(t!=null)_.current=!0,e=t;else if(_.current)e=o;else{v();return}if(e===void 0){v();return}g.current=!0,a(u.current,e)},[t,r,s,a,n,o,u,v]),h.useEffect(()=>v,[v]),i??o}function j(e){let{enabled:t=!0,value:n,id:r,name:i,controlRef:a,commit:o}=e,{formRef:s}=T(),{invalid:c,markedDirtyRef:l,validityData:u,setValidityData:p}=C(),m=d(e.getValue);f(()=>{if(!t)return;let e=n;e===void 0&&(e=m()),u.initialValue===null&&e!==null&&p(t=>({...t,initialValue:e}))},[t,p,n,u.initialValue,m]),f(()=>{!t||!r||s.current.fields.set(r,{getValue:m,name:i,controlRef:a,validityData:O(u,c),validate(e=!0){let t=n;t===void 0&&(t=m()),l.current=!0,e?g.flushSync(()=>o(t)):o(t)}})},[o,a,t,s,m,r,c,l,i,u,n]),f(()=>{let e=s.current.fields;return()=>{r&&e.delete(r)}},[s,r])}var M=h.forwardRef(function(e,t){let{className:n,render:r,orientation:i=`horizontal`,...a}=e;return s(`div`,e,{state:{orientation:i},ref:t,props:[{role:`separator`,"aria-orientation":i},a]})}),N=r(),P=t();function F(e){let t=(0,N.c)(10),n,r,i;t[0]===e?(n=t[1],r=t[2],i=t[3]):({className:n,orientation:i,...r}=e,t[0]=e,t[1]=n,t[2]=r,t[3]=i);let a=i===void 0?`horizontal`:i,o;t[4]===n?o=t[5]:(o=u(`shrink-0 bg-border data-[orientation=horizontal]:h-px data-[orientation=horizontal]:w-full data-[orientation=vertical]:w-px data-[orientation=vertical]:self-stretch`,n),t[4]=n,t[5]=o);let s;return t[6]!==a||t[7]!==r||t[8]!==o?(s=(0,P.jsx)(M,{className:o,"data-slot":`separator`,orientation:a,...r}),t[6]=a,t[7]=r,t[8]=o,t[9]=s):s=t[9],s}export{D as a,x as c,k as i,j as n,T as o,A as r,C as s,F as t};
|
||||
import{a as e,n as t,r as n,t as r}from"./compiler-runtime.js";import{l as i,m as a,n as o,p as s,u as c}from"./dist.js";import{I as l}from"./SignatureV4.js";import{c as u,o as d,y as f}from"./button.js";import{b as p}from"./createBaseUIEventDetails.js";var m=e(n()),h=function(e){return e.disabled=`data-disabled`,e.valid=`data-valid`,e.invalid=`data-invalid`,e.touched=`data-touched`,e.dirty=`data-dirty`,e.filled=`data-filled`,e.focused=`data-focused`,e}({}),g={badInput:!1,customError:!1,patternMismatch:!1,rangeOverflow:!1,rangeUnderflow:!1,stepMismatch:!1,tooLong:!1,tooShort:!1,typeMismatch:!1,valid:null,valueMissing:!1},_={valid:null,touched:!1,dirty:!1,filled:!1,focused:!1},v={disabled:!1,..._},y={valid(e){return e===null?null:e?{[h.valid]:``}:{[h.invalid]:``}}},b=m.createContext({invalid:void 0,name:void 0,validityData:{state:g,errors:[],error:``,value:``,initialValue:null},setValidityData:c,disabled:void 0,touched:_.touched,setTouched:c,dirty:_.dirty,setDirty:c,filled:_.filled,setFilled:c,focused:_.focused,setFocused:c,validate:()=>null,validationMode:`onSubmit`,validationDebounceTime:0,shouldValidateOnChange:()=>!1,state:v,markedDirtyRef:{current:!1},registerFieldControl:c,validation:{getValidationProps:(e=i)=>e,getInputValidationProps:(e=i)=>e,inputRef:{current:null},commit:async()=>{}}});function x(e=!0){let t=m.useContext(b);if(t.setValidityData===c&&!e)throw Error(a(28));return t}var S=m.createContext({controlId:void 0,registerControlId:c,labelId:void 0,setLabelId:c,messageIds:[],setMessageIds:c,getDescriptionProps:e=>e});function C(){return m.useContext(S)}function w({controlled:e,default:t,name:n,state:r=`value`}){let{current:i}=m.useRef(e!==void 0),[a,o]=m.useState(t);return[i?e:a,m.useCallback(e=>{i||o(e)},[])]}function T(e,t){let{enabled:n=!0,getValue:r,id:i,value:a}=t,{registerFieldControl:o}=x(),s=m.useRef(null);s.current||=Symbol(),d(()=>{let t=s.current;if(!(!t||!n))return o(t,{controlRef:e,getValue:r,id:i,value:a}),()=>{o(t,void 0)}},[e,n,r,i,o,a])}function E(e={}){let{id:t,implicit:n=!1,controlRef:r}=e,{controlId:i,registerControlId:a}=C(),o=p(t),l=n?i:void 0,h=s(()=>Symbol(`labelable-control`)),g=m.useRef(!1),_=m.useRef(t!=null),v=u(()=>{!g.current||a===c||(g.current=!1,a(h.current,void 0))});return d(()=>{if(a===c)return;let e;if(n){let n=r?.current;e=f(n)&&n.closest(`label`)!=null?t??null:l??o}else if(t!=null)_.current=!0,e=t;else if(_.current)e=o;else{v();return}if(e===void 0){v();return}g.current=!0,a(h.current,e)},[t,r,l,a,n,o,h,v]),m.useEffect(()=>v,[v]),i??o}var D=m.forwardRef(function(e,t){let{className:n,render:r,orientation:i=`horizontal`,style:a,...s}=e;return o(`div`,e,{state:{orientation:i},ref:t,props:[{role:`separator`,"aria-orientation":i},s]})}),O=r(),k=t();function A(e){let t=(0,O.c)(10),n,r,i;t[0]===e?(n=t[1],r=t[2],i=t[3]):({className:n,orientation:i,...r}=e,t[0]=e,t[1]=n,t[2]=r,t[3]=i);let a=i===void 0?`horizontal`:i,o;t[4]===n?o=t[5]:(o=l(`shrink-0 bg-border data-[orientation=horizontal]:h-px data-[orientation=horizontal]:w-full data-[orientation=vertical]:w-px data-[orientation=vertical]:self-stretch`,n),t[4]=n,t[5]=o);let s;return t[6]!==a||t[7]!==r||t[8]!==o?(s=(0,k.jsx)(D,{className:o,"data-slot":`separator`,orientation:a,...r}),t[6]=a,t[7]=r,t[8]=o,t[9]=s):s=t[9],s}export{C as a,w as i,E as n,x as o,T as r,y as s,A as t};
|
||||
File diff suppressed because one or more lines are too long
+1
-12
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1 +0,0 @@
|
||||
import{a as e,r as t}from"./compiler-runtime.js";import{hn as n}from"./awsClient.js";import{p as r}from"./dist.js";import{c as i,o as a}from"./button.js";var o=e(n()),s=e(t()),c=[];function l(e){s.useEffect(e,c)}var u=null;globalThis.requestAnimationFrame;var d=new class{callbacks=[];callbacksCount=0;nextId=1;startId=1;isScheduled=!1;tick=e=>{this.isScheduled=!1;let t=this.callbacks,n=this.callbacksCount;if(this.callbacks=[],this.callbacksCount=0,this.startId=this.nextId,n>0)for(let n=0;n<t.length;n+=1)t[n]?.(e)};request(e){let t=this.nextId;return this.nextId+=1,this.callbacks.push(e),this.callbacksCount+=1,this.isScheduled||=(requestAnimationFrame(this.tick),!0),t}cancel(e){let t=e-this.startId;t<0||t>=this.callbacks.length||(this.callbacks[t]=null,--this.callbacksCount)}},f=class e{static create(){return new e}static request(e){return d.request(e)}static cancel(e){return d.cancel(e)}currentId=u;request(e){this.cancel(),this.currentId=d.request(()=>{this.currentId=u,e()})}cancel=()=>{this.currentId!==u&&(d.cancel(this.currentId),this.currentId=u)};disposeEffect=()=>this.cancel};function p(){let e=r(f.create).current;return l(e.disposeEffect),e}function m(e){return e==null?e:`current`in e?e.current:e}var h=function(e){return e.startingStyle=`data-starting-style`,e.endingStyle=`data-ending-style`,e}({}),g={[h.startingStyle]:``},_={[h.endingStyle]:``},v={transitionStatus(e){return e===`starting`?g:e===`ending`?_:null}};function y(e,t=!1,n=!0){let r=p();return i((i,a=null)=>{r.cancel();function s(){o.flushSync(i)}let c=m(e);if(c==null)return;let l=c;if(typeof l.getAnimations!=`function`||globalThis.BASE_UI_ANIMATIONS_DISABLED)i();else{function e(){let e=h.startingStyle;if(!l.hasAttribute(e)){r.request(i);return}let t=new MutationObserver(()=>{l.hasAttribute(e)||(t.disconnect(),i())});t.observe(l,{attributes:!0,attributeFilter:[e]}),a?.addEventListener(`abort`,()=>t.disconnect(),{once:!0})}function i(){Promise.all(l.getAnimations().map(e=>e.finished)).then(()=>{a?.aborted||s()}).catch(()=>{let e=l.getAnimations();if(n){if(a?.aborted)return;s()}else e.length>0&&e.some(e=>e.pending||e.playState!==`finished`)&&i()})}if(t){e();return}r.request(i)}})}function b(e){let{enabled:t=!0,open:n,ref:r,onComplete:a}=e,o=i(a),c=y(r,n,!1);s.useEffect(()=>{if(!t)return;let e=new AbortController;return c(o,e.signal),()=>{e.abort()}},[t,n,o,c])}function x(e,t=!1,n=!1){let[r,i]=s.useState(e&&t?`idle`:void 0),[o,c]=s.useState(e);return e&&!o&&(c(!0),i(`starting`)),!e&&o&&r!==`ending`&&!n&&i(`ending`),!e&&!o&&r===`ending`&&i(void 0),a(()=>{if(!e&&o&&r!==`ending`&&n){let e=f.request(()=>{i(`ending`)});return()=>{f.cancel(e)}}},[e,o,r,n]),a(()=>{if(!e||t)return;let n=f.request(()=>{i(void 0)});return()=>{f.cancel(n)}},[t,e]),a(()=>{if(!e||!t)return;e&&o&&r!==`idle`&&i(`starting`);let n=f.request(()=>{i(`idle`)});return()=>{f.cancel(n)}},[t,e,o,i,r]),s.useMemo(()=>({mounted:o,setMounted:c,transitionStatus:r}),[o,r])}export{v as a,p as c,h as i,l,b as n,m as o,y as r,f as s,x as t};
|
||||
+2
-2
@@ -22,11 +22,11 @@
|
||||
<link rel="modulepreload" crossorigin href="/assets/dist.js">
|
||||
<link rel="modulepreload" crossorigin href="/assets/button.js">
|
||||
<link rel="modulepreload" crossorigin href="/assets/createBaseUIEventDetails.js">
|
||||
<link rel="modulepreload" crossorigin href="/assets/useTransitionStatus.js">
|
||||
<link rel="modulepreload" crossorigin href="/assets/addEventListener.js">
|
||||
<link rel="modulepreload" crossorigin href="/assets/useStore.js">
|
||||
<link rel="modulepreload" crossorigin href="/assets/useOpenInteractionType.js">
|
||||
<link rel="modulepreload" crossorigin href="/assets/DialogTitle.js">
|
||||
<link rel="modulepreload" crossorigin href="/assets/getDisabledMountTransitionStyles.js">
|
||||
<link rel="modulepreload" crossorigin href="/assets/usePositioner.js">
|
||||
<link rel="modulepreload" crossorigin href="/assets/separator.js">
|
||||
<link rel="modulepreload" crossorigin href="/assets/input.js">
|
||||
<link rel="modulepreload" crossorigin href="/assets/admin-context.js">
|
||||
|
||||
@@ -14,19 +14,19 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@aws-crypto/sha256-browser": "^5.2.0",
|
||||
"@aws-sdk/client-ec2": "^3.1029.0",
|
||||
"@aws-sdk/client-elastic-load-balancing-v2": "^3.1029.0",
|
||||
"@aws-sdk/client-iam": "^3.1029.0",
|
||||
"@aws-sdk/client-s3": "^3.1029.0",
|
||||
"@aws-sdk/lib-storage": "^3.1029.0",
|
||||
"@base-ui/react": "^1.3.0",
|
||||
"@aws-sdk/client-ec2": "^3.1032.0",
|
||||
"@aws-sdk/client-elastic-load-balancing-v2": "^3.1032.0",
|
||||
"@aws-sdk/client-iam": "^3.1032.0",
|
||||
"@aws-sdk/client-s3": "^3.1032.0",
|
||||
"@aws-sdk/lib-storage": "^3.1032.0",
|
||||
"@base-ui/react": "^1.4.0",
|
||||
"@fontsource-variable/geist": "^5.2.8",
|
||||
"@fontsource-variable/jetbrains-mono": "^5.2.8",
|
||||
"@hookform/resolvers": "^5.2.2",
|
||||
"@smithy/protocol-http": "^5.3.13",
|
||||
"@smithy/signature-v4": "^5.3.13",
|
||||
"@tanstack/react-query": "^5.99.0",
|
||||
"@tanstack/react-router": "^1.168.18",
|
||||
"@smithy/protocol-http": "^5.3.14",
|
||||
"@smithy/signature-v4": "^5.3.14",
|
||||
"@tanstack/react-query": "^5.99.1",
|
||||
"@tanstack/react-router": "^1.168.23",
|
||||
"class-variance-authority": "^0.7.1",
|
||||
"clsx": "^2.1.1",
|
||||
"lucide-react": "^1.8.0",
|
||||
@@ -38,28 +38,28 @@
|
||||
"zod": "^4.3.6"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@rolldown/plugin-babel": "^0.2.2",
|
||||
"@rolldown/plugin-babel": "^0.2.3",
|
||||
"@tailwindcss/vite": "^4.2.2",
|
||||
"@tanstack/eslint-plugin-query": "^5.99.0",
|
||||
"@tanstack/eslint-plugin-query": "^5.99.1",
|
||||
"@tanstack/eslint-plugin-router": "^1.161.6",
|
||||
"@tanstack/router-plugin": "^1.167.18",
|
||||
"@tanstack/router-plugin": "^1.167.22",
|
||||
"@testing-library/jest-dom": "^6.9.1",
|
||||
"@testing-library/react": "^16.3.2",
|
||||
"@testing-library/user-event": "^14.6.1",
|
||||
"@types/node": "24.12.2",
|
||||
"@types/react": "^19.2.14",
|
||||
"@types/react-dom": "^19.2.3",
|
||||
"@typescript/native-preview": "7.0.0-dev.20260411.1",
|
||||
"@typescript/native-preview": "7.0.0-dev.20260418.1",
|
||||
"@vitejs/plugin-basic-ssl": "^2.3.0",
|
||||
"@vitejs/plugin-react": "^6.0.1",
|
||||
"@vitest/coverage-v8": "^4.1.4",
|
||||
"babel-plugin-react-compiler": "^1.0.0",
|
||||
"happy-dom": "^20.8.9",
|
||||
"oxfmt": "^0.44.0",
|
||||
"oxlint": "^1.59.0",
|
||||
"oxlint-tsgolint": "^0.20.0",
|
||||
"typescript": "^6.0.2",
|
||||
"ultracite": "7.5.6",
|
||||
"happy-dom": "^20.9.0",
|
||||
"oxfmt": "^0.45.0",
|
||||
"oxlint": "^1.60.0",
|
||||
"oxlint-tsgolint": "^0.21.1",
|
||||
"typescript": "^6.0.3",
|
||||
"ultracite": "7.6.0",
|
||||
"vite": "^8.0.8",
|
||||
"vitest": "^4.1.4"
|
||||
},
|
||||
|
||||
+1153
-1158
File diff suppressed because it is too large
Load Diff
@@ -348,8 +348,8 @@ var AvailableImages = map[string]Images{
|
||||
Arch: "x86_64",
|
||||
Platform: "Linux/UNIX",
|
||||
CreatedAt: time.Date(2026, 03, 27, 0, 0, 0, 0, time.UTC),
|
||||
URL: "https://d2yp8ipz5jfqcw.cloudfront.net/alb-alpine-3.21.6-x86_64.raw",
|
||||
Checksum: "https://d2yp8ipz5jfqcw.cloudfront.net/alb-alpine-3.21.6-x86_64.raw.sha512",
|
||||
URL: "https://iso.mulgadc.com/system-ami/lb-alpine-3.21.6-x86_64.raw",
|
||||
Checksum: "https://iso.mulgadc.com/system-ami/lb-alpine-3.21.6-x86_64.raw.sha512",
|
||||
ChecksumType: "sha512",
|
||||
BootMode: "bios",
|
||||
Starred: false,
|
||||
|
||||
+68
-2
@@ -13,6 +13,14 @@ import (
|
||||
"github.com/nats-io/nats.go"
|
||||
)
|
||||
|
||||
// Sentinel errors for TLS certificate configuration failures in ConnectNATS.
|
||||
// Callers can use errors.Is to detect permanent TLS errors without relying
|
||||
// on error message text.
|
||||
var (
|
||||
ErrCACertRead = errors.New("failed to read CA cert")
|
||||
ErrCACertParse = errors.New("failed to parse CA cert")
|
||||
)
|
||||
|
||||
// ConnectNATS establishes a connection to a NATS server with standard reconnect
|
||||
// handling and logging. If token is non-empty, token authentication is used.
|
||||
// If caCertPath is non-empty, TLS is enabled using the given CA certificate.
|
||||
@@ -35,11 +43,11 @@ func ConnectNATS(host, token, caCertPath string) (*nats.Conn, error) {
|
||||
if caCertPath != "" {
|
||||
caCert, err := os.ReadFile(caCertPath)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("read CA cert %s: %w", caCertPath, err)
|
||||
return nil, fmt.Errorf("%w %s: %v", ErrCACertRead, caCertPath, err)
|
||||
}
|
||||
pool := x509.NewCertPool()
|
||||
if !pool.AppendCertsFromPEM(caCert) {
|
||||
return nil, fmt.Errorf("failed to parse CA cert from %s", caCertPath)
|
||||
return nil, fmt.Errorf("%w from %s", ErrCACertParse, caCertPath)
|
||||
}
|
||||
opts = append(opts, nats.Secure(&tls.Config{
|
||||
RootCAs: pool,
|
||||
@@ -55,6 +63,64 @@ func ConnectNATS(host, token, caCertPath string) (*nats.Conn, error) {
|
||||
return nc, nil
|
||||
}
|
||||
|
||||
// retryConfig holds parameters for ConnectNATSWithRetry.
|
||||
type retryConfig struct {
|
||||
maxWait time.Duration
|
||||
retryDelay time.Duration
|
||||
}
|
||||
|
||||
// RetryOption configures ConnectNATSWithRetry behavior.
|
||||
type RetryOption func(*retryConfig)
|
||||
|
||||
// WithMaxWait sets the maximum total time to keep retrying before giving up.
|
||||
func WithMaxWait(d time.Duration) RetryOption {
|
||||
return func(c *retryConfig) { c.maxWait = d }
|
||||
}
|
||||
|
||||
// WithRetryDelay sets the initial delay between retries (doubles each attempt, capped at 10s).
|
||||
func WithRetryDelay(d time.Duration) RetryOption {
|
||||
return func(c *retryConfig) { c.retryDelay = d }
|
||||
}
|
||||
|
||||
// ConnectNATSWithRetry calls ConnectNATS in a retry loop with exponential
|
||||
// backoff. It retries for up to 5 minutes (default) before giving up. TLS
|
||||
// configuration errors (ErrCACertRead, ErrCACertParse) are permanent and
|
||||
// cause an immediate return without retrying.
|
||||
func ConnectNATSWithRetry(host, token, caCertPath string, opts ...RetryOption) (*nats.Conn, error) {
|
||||
cfg := retryConfig{
|
||||
maxWait: 5 * time.Minute,
|
||||
retryDelay: 500 * time.Millisecond,
|
||||
}
|
||||
for _, o := range opts {
|
||||
o(&cfg)
|
||||
}
|
||||
|
||||
start := time.Now()
|
||||
for {
|
||||
nc, err := ConnectNATS(host, token, caCertPath)
|
||||
if err == nil {
|
||||
if time.Since(start) > time.Second {
|
||||
slog.Info("NATS connection established", "elapsed", time.Since(start).Round(time.Second))
|
||||
}
|
||||
return nc, nil
|
||||
}
|
||||
|
||||
// TLS configuration errors are permanent — retrying will not help.
|
||||
if errors.Is(err, ErrCACertRead) || errors.Is(err, ErrCACertParse) {
|
||||
return nil, fmt.Errorf("NATS TLS configuration error: %w", err)
|
||||
}
|
||||
|
||||
elapsed := time.Since(start)
|
||||
if elapsed >= cfg.maxWait {
|
||||
return nil, fmt.Errorf("NATS connect failed after %s: %w", elapsed.Round(time.Second), err)
|
||||
}
|
||||
|
||||
slog.Warn("NATS not ready, retrying...", "error", err, "elapsed", elapsed.Round(time.Second), "retryIn", cfg.retryDelay)
|
||||
time.Sleep(cfg.retryDelay)
|
||||
cfg.retryDelay = min(cfg.retryDelay*2, 10*time.Second)
|
||||
}
|
||||
}
|
||||
|
||||
// AccountIDHeader is the NATS message header key used to pass the caller's
|
||||
// AWS account ID from the gateway to daemon handlers.
|
||||
const AccountIDHeader = "X-Account-ID"
|
||||
|
||||
@@ -90,7 +90,7 @@ func TestConnectNATS_BadAddress(t *testing.T) {
|
||||
func TestConnectNATS_MissingCACert(t *testing.T) {
|
||||
_, err := ConnectNATS("nats://127.0.0.1:4222", "", "/nonexistent/ca.pem")
|
||||
require.Error(t, err)
|
||||
assert.Contains(t, err.Error(), "read CA cert")
|
||||
assert.ErrorIs(t, err, ErrCACertRead)
|
||||
assert.Contains(t, err.Error(), "/nonexistent/ca.pem")
|
||||
}
|
||||
|
||||
@@ -101,7 +101,7 @@ func TestConnectNATS_MalformedCACert(t *testing.T) {
|
||||
|
||||
_, err := ConnectNATS("nats://127.0.0.1:4222", "", badCert)
|
||||
require.Error(t, err)
|
||||
assert.Contains(t, err.Error(), "failed to parse CA cert")
|
||||
assert.ErrorIs(t, err, ErrCACertParse)
|
||||
}
|
||||
|
||||
// generateTestCA creates an ephemeral CA cert+key and writes PEM files to dir.
|
||||
@@ -535,3 +535,41 @@ func TestAccountIDFromMsg_NilHeader(t *testing.T) {
|
||||
msg := &nats.Msg{Subject: "test"}
|
||||
assert.Equal(t, "", AccountIDFromMsg(msg))
|
||||
}
|
||||
|
||||
// --- ConnectNATSWithRetry tests ---
|
||||
|
||||
func TestConnectNATSWithRetry_Success(t *testing.T) {
|
||||
ns := startTestNATSServer(t)
|
||||
|
||||
nc, err := ConnectNATSWithRetry(ns.ClientURL(), "", "")
|
||||
require.NoError(t, err)
|
||||
defer nc.Close()
|
||||
assert.True(t, nc.IsConnected())
|
||||
}
|
||||
|
||||
func TestConnectNATSWithRetry_RetriesOnFailure(t *testing.T) {
|
||||
start := time.Now()
|
||||
_, err := ConnectNATSWithRetry("nats://127.0.0.1:14222", "", "",
|
||||
WithMaxWait(500*time.Millisecond),
|
||||
WithRetryDelay(50*time.Millisecond),
|
||||
)
|
||||
elapsed := time.Since(start)
|
||||
|
||||
require.Error(t, err)
|
||||
assert.Contains(t, err.Error(), "NATS connect failed")
|
||||
assert.GreaterOrEqual(t, elapsed, 100*time.Millisecond, "should have retried at least once")
|
||||
assert.Less(t, elapsed, 5*time.Second, "should fail within a few seconds")
|
||||
}
|
||||
|
||||
func TestConnectNATSWithRetry_TLSErrorNoRetry(t *testing.T) {
|
||||
start := time.Now()
|
||||
_, err := ConnectNATSWithRetry("nats://127.0.0.1:4222", "", "/nonexistent/ca.pem",
|
||||
WithMaxWait(5*time.Second),
|
||||
)
|
||||
elapsed := time.Since(start)
|
||||
|
||||
require.Error(t, err)
|
||||
assert.ErrorIs(t, err, ErrCACertRead)
|
||||
assert.Contains(t, err.Error(), "NATS TLS configuration error")
|
||||
assert.Less(t, elapsed, time.Second, "should fail immediately without retrying")
|
||||
}
|
||||
|
||||
@@ -87,6 +87,14 @@ type VM struct {
|
||||
PublicIP string `json:"public_ip,omitempty"`
|
||||
PublicIPPool string `json:"public_ip_pool,omitempty"`
|
||||
|
||||
// PublicIPAllocID / PublicIPAssocID are set when the public IP was
|
||||
// allocated through the EIP service (handlers/ec2/eip) rather than
|
||||
// directly via externalIPAM. Presence signals that teardown must go
|
||||
// back through the EIP service (DisassociateAddress + ReleaseAddress)
|
||||
// so the EIP KV record is removed.
|
||||
PublicIPAllocID string `json:"public_ip_alloc_id,omitempty"`
|
||||
PublicIPAssocID string `json:"public_ip_assoc_id,omitempty"`
|
||||
|
||||
// DevMAC is the MAC for the dev/hostfwd NIC (DEV_NETWORKING mode).
|
||||
// Set before cloud-init ISO generation so netplan can suppress its default route.
|
||||
DevMAC string `json:"dev_mac,omitempty"`
|
||||
|
||||
Reference in New Issue
Block a user