forked from cerc-io/stack-orchestrator
Compare commits
6
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
15faed00de | ||
|
|
6bef0c5b2f | ||
|
|
f27da19808 | ||
|
|
2dd54892a1 | ||
|
|
ab0e70ed83 | ||
|
|
c319e90ddd |
@@ -32,8 +32,9 @@ from stack_orchestrator.build import build_containers
|
||||
@click.option('--source-repo', help="directory containing the webapp to build", required=True)
|
||||
@click.option("--force-rebuild", is_flag=True, default=False, help="Override dependency checking -- always rebuild")
|
||||
@click.option("--extra-build-args", help="Supply extra arguments to build")
|
||||
@click.option("--tag", help="Container tag (default: cerc/<app_name>:local)")
|
||||
@click.pass_context
|
||||
def command(ctx, base_container, source_repo, force_rebuild, extra_build_args):
|
||||
def command(ctx, base_container, source_repo, force_rebuild, extra_build_args, tag):
|
||||
'''build the specified webapp container'''
|
||||
|
||||
quiet = ctx.obj.quiet
|
||||
@@ -70,8 +71,11 @@ def command(ctx, base_container, source_repo, force_rebuild, extra_build_args):
|
||||
container_build_env["CERC_CONTAINER_BUILD_DOCKERFILE"] = os.path.join(container_build_dir,
|
||||
base_container.replace("/", "-"),
|
||||
"Dockerfile.webapp")
|
||||
webapp_name = os.path.abspath(source_repo).split(os.path.sep)[-1]
|
||||
container_build_env["CERC_CONTAINER_BUILD_TAG"] = f"cerc/{webapp_name}:local"
|
||||
if not tag:
|
||||
webapp_name = os.path.abspath(source_repo).split(os.path.sep)[-1]
|
||||
container_build_env["CERC_CONTAINER_BUILD_TAG"] = f"cerc/{webapp_name}:local"
|
||||
else:
|
||||
container_build_env["CERC_CONTAINER_BUILD_TAG"] = tag
|
||||
|
||||
build_containers.process_container(None, base_container, container_build_dir, container_build_env, dev_root_path, quiet,
|
||||
verbose, dry_run, continue_on_error)
|
||||
|
||||
@@ -13,12 +13,16 @@
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http:#www.gnu.org/licenses/>.
|
||||
|
||||
cluster_name_prefix = "laconic-"
|
||||
stack_file_name = "stack.yml"
|
||||
spec_file_name = "spec.yml"
|
||||
config_file_name = "config.env"
|
||||
deployment_file_name = "deployment.yml"
|
||||
compose_dir_name = "compose"
|
||||
compose_deploy_type = "compose"
|
||||
k8s_kind_deploy_type = "k8s-kind"
|
||||
k8s_deploy_type = "k8s"
|
||||
cluster_id_key = "cluster-id"
|
||||
kube_config_key = "kube-config"
|
||||
deploy_to_key = "deploy-to"
|
||||
network_key = "network"
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
version: "3.2"
|
||||
|
||||
services:
|
||||
proxy-server:
|
||||
image: cerc/watcher-ts:local
|
||||
restart: on-failure
|
||||
working_dir: /app/packages/cli
|
||||
environment:
|
||||
ENABLE_PROXY: ${ENABLE_PROXY:-true}
|
||||
PROXY_UPSTREAM: ${CERC_PROXY_UPSTREAM}
|
||||
PROXY_ORIGIN_HEADER: ${CERC_PROXY_ORIGIN_HEADER}
|
||||
command: ["sh", "-c", "./run.sh"]
|
||||
volumes:
|
||||
- ../config/proxy-server/run.sh:/app/packages/cli/run.sh
|
||||
ports:
|
||||
- "4000"
|
||||
healthcheck:
|
||||
test: ["CMD", "nc", "-v", "localhost", "4000"]
|
||||
interval: 20s
|
||||
timeout: 5s
|
||||
retries: 15
|
||||
start_period: 10s
|
||||
@@ -0,0 +1,17 @@
|
||||
version: "3.2"
|
||||
|
||||
services:
|
||||
uniswap-interface:
|
||||
image: cerc/uniswap-interface:local
|
||||
restart: on-failure
|
||||
environment:
|
||||
- REACT_APP_INFURA_KEY=${CERC_INFURA_KEY}
|
||||
- REACT_APP_AWS_API_ENDPOINT=${CERC_UNISWAP_GQL}
|
||||
command: ["./build-app.sh"]
|
||||
volumes:
|
||||
- app_builds:/app-builds
|
||||
- ../config/uniswap-interface/build-app.sh:/app/build-app.sh
|
||||
|
||||
volumes:
|
||||
app_builds:
|
||||
app_globs:
|
||||
@@ -0,0 +1,46 @@
|
||||
version: '3.7'
|
||||
|
||||
services:
|
||||
urbit-fake-ship:
|
||||
restart: unless-stopped
|
||||
image: tloncorp/vere
|
||||
environment:
|
||||
CERC_IPFS_GLOB_HOST_ENDPOINT: ${CERC_IPFS_GLOB_HOST_ENDPOINT:-http://ipfs-glob-host:5001}
|
||||
CERC_IPFS_SERVER_ENDPOINT: ${CERC_IPFS_SERVER_ENDPOINT:-http://ipfs-glob-host:8080}
|
||||
entrypoint: ["bash", "-c", "./run-urbit-ship.sh && ./deploy-uniswap-app.sh && tail -f /dev/null"]
|
||||
volumes:
|
||||
- urbit_data:/urbit
|
||||
- app_builds:/app-builds
|
||||
- app_globs:/app-globs
|
||||
- ../config/urbit/run-urbit-ship.sh:/urbit/run-urbit-ship.sh
|
||||
- ../config/uniswap-interface/deploy-uniswap-app.sh:/urbit/deploy-uniswap-app.sh
|
||||
ports:
|
||||
- "80"
|
||||
healthcheck:
|
||||
test: ["CMD", "nc", "-v", "localhost", "80"]
|
||||
interval: 20s
|
||||
timeout: 5s
|
||||
retries: 15
|
||||
start_period: 10s
|
||||
|
||||
ipfs-glob-host:
|
||||
image: ipfs/kubo:master-2023-02-20-714a968
|
||||
volumes:
|
||||
- ipfs-import:/import
|
||||
- ipfs-data:/data/ipfs
|
||||
ports:
|
||||
- "8080"
|
||||
- "5001"
|
||||
healthcheck:
|
||||
test: ["CMD", "nc", "-v", "localhost", "5001"]
|
||||
interval: 20s
|
||||
timeout: 5s
|
||||
retries: 15
|
||||
start_period: 10s
|
||||
|
||||
volumes:
|
||||
urbit_data:
|
||||
app_builds:
|
||||
app_globs:
|
||||
ipfs-import:
|
||||
ipfs-data:
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
#!/bin/sh
|
||||
|
||||
if [ "$ENABLE_PROXY" = "true" ]; then
|
||||
echo "Proxy server enabled"
|
||||
yarn proxy
|
||||
else
|
||||
echo "Proxy server disabled, exiting"
|
||||
exit 0
|
||||
fi
|
||||
@@ -0,0 +1,18 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
if [ -n "$CERC_SCRIPT_DEBUG" ]; then
|
||||
set -x
|
||||
fi
|
||||
|
||||
# Check and exit if a deployment already exists (on restarts)
|
||||
if [ -d /app-builds/uniswap/build ]; then
|
||||
echo "Build already exists, remove volume to rebuild"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
yarn build
|
||||
|
||||
# Move build to app-builds so urbit can deploy it
|
||||
mkdir /app-builds/uniswap
|
||||
cp -r ./build /app-builds/uniswap/
|
||||
@@ -0,0 +1,149 @@
|
||||
#!/bin/bash
|
||||
|
||||
if [ -n "$CERC_SCRIPT_DEBUG" ]; then
|
||||
set -x
|
||||
fi
|
||||
|
||||
echo "Using IPFS endpoint ${CERC_IPFS_GLOB_HOST_ENDPOINT} for hosting globs"
|
||||
echo "Using IPFS server endpoint ${CERC_IPFS_SERVER_ENDPOINT} for reading glob files"
|
||||
ipfs_host_endpoint=${CERC_IPFS_GLOB_HOST_ENDPOINT}
|
||||
ipfs_server_endpoint=${CERC_IPFS_SERVER_ENDPOINT}
|
||||
|
||||
uniswap_app_build='/app-builds/uniswap/build'
|
||||
uniswap_desk_dir='/urbit/zod/uniswap'
|
||||
|
||||
if [ -d ${uniswap_desk_dir} ]; then
|
||||
echo "Uniswap desk dir already exists, skipping deployment..."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Fire curl requests to perform operations on the ship
|
||||
dojo () {
|
||||
curl -s --data '{"source":{"dojo":"'"$1"'"},"sink":{"stdout":null}}' http://localhost:12321
|
||||
}
|
||||
|
||||
hood () {
|
||||
curl -s --data '{"source":{"dojo":"+hood/'"$1"'"},"sink":{"app":"hood"}}' http://localhost:12321
|
||||
}
|
||||
|
||||
# Create/mount a uniswap desk
|
||||
hood "merge %uniswap our %landscape"
|
||||
hood "mount %uniswap"
|
||||
|
||||
# Loop until the uniswap build appears
|
||||
while [ ! -d ${uniswap_app_build} ]; do
|
||||
echo "Uniswap app build not found, retrying in 5s..."
|
||||
sleep 5
|
||||
done
|
||||
echo "Build found..."
|
||||
|
||||
# Copy over build to desk data dir
|
||||
cp -r ${uniswap_app_build} ${uniswap_desk_dir}
|
||||
|
||||
# Create a mark file for .map file type
|
||||
cat << EOF > "${uniswap_desk_dir}/mar/map.hoon"
|
||||
::
|
||||
:::: /hoon/map/mar
|
||||
:: Mark for js source maps
|
||||
/? 310
|
||||
::
|
||||
=, eyre
|
||||
|_ mud=@
|
||||
++ grow
|
||||
|%
|
||||
++ mime [/application/octet-stream (as-octs:mimes:html (@t mud))]
|
||||
--
|
||||
++ grab
|
||||
|% :: convert from
|
||||
++ mime |=([p=mite q=octs] (@t q.q))
|
||||
++ noun cord :: clam from %noun
|
||||
--
|
||||
++ grad %mime
|
||||
--
|
||||
EOF
|
||||
|
||||
# Create a mark file for .woff file type
|
||||
cat << EOF > "${uniswap_desk_dir}/mar/woff.hoon"
|
||||
|_ dat=octs
|
||||
++ grow
|
||||
|%
|
||||
++ mime [/font/woff dat]
|
||||
--
|
||||
++ grab
|
||||
|%
|
||||
++ mime |=([=mite =octs] octs)
|
||||
++ noun octs
|
||||
--
|
||||
++ grad %mime
|
||||
--
|
||||
EOF
|
||||
|
||||
# Create a mark file for .ttf file type
|
||||
cat << EOF > "${uniswap_desk_dir}/mar/ttf.hoon"
|
||||
|_ dat=octs
|
||||
++ grow
|
||||
|%
|
||||
++ mime [/font/ttf dat]
|
||||
--
|
||||
++ grab
|
||||
|%
|
||||
++ mime |=([=mite =octs] octs)
|
||||
++ noun octs
|
||||
--
|
||||
++ grad %mime
|
||||
--
|
||||
EOF
|
||||
|
||||
rm "${uniswap_desk_dir}/desk.bill"
|
||||
rm "${uniswap_desk_dir}/desk.ship"
|
||||
|
||||
# Commit changes and create a glob
|
||||
hood "commit %uniswap"
|
||||
dojo "-landscape!make-glob %uniswap /build"
|
||||
|
||||
glob_file=$(ls -1 -c zod/.urb/put | head -1)
|
||||
echo "Created glob file: ${glob_file}"
|
||||
|
||||
upload_response=$(curl -X POST -F file=@./zod/.urb/put/${glob_file} ${ipfs_host_endpoint}/api/v0/add)
|
||||
glob_cid=$(echo "$upload_response" | grep -o '"Hash":"[^"]*' | sed 's/"Hash":"//')
|
||||
|
||||
echo "Glob file uploaded to IFPS:"
|
||||
echo "{ cid: ${glob_cid}, filename: ${glob_file} }"
|
||||
|
||||
# Curl and wait for the glob to be hosted
|
||||
glob_url="${ipfs_server_endpoint}/ipfs/${glob_cid}?filename=${glob_file}"
|
||||
|
||||
echo "Checking if glob file hosted at ${glob_url}"
|
||||
while true; do
|
||||
response=$(curl -sL -w "%{http_code}" -o /dev/null "$glob_url")
|
||||
|
||||
if [ $response -eq 200 ]; then
|
||||
echo "File found at $glob_url"
|
||||
break # Exit the loop if the file is found
|
||||
else
|
||||
echo "File not found. Retrying in a few seconds..."
|
||||
sleep 5
|
||||
fi
|
||||
done
|
||||
|
||||
glob_hash=$(echo "$glob_file" | sed "s/glob-\([a-z0-9\.]*\).glob/\1/")
|
||||
|
||||
# Update the docket file
|
||||
cat << EOF > "${uniswap_desk_dir}/desk.docket-0"
|
||||
:~ title+'Uniswap'
|
||||
info+'Self-hosted uniswap frontend.'
|
||||
color+0xcd.75df
|
||||
image+'https://logowik.com/content/uploads/images/uniswap-uni7403.jpg'
|
||||
base+'uniswap'
|
||||
glob-http+['${glob_url}' ${glob_hash}]
|
||||
version+[0 0 1]
|
||||
website+'https://uniswap.org/'
|
||||
license+'MIT'
|
||||
==
|
||||
EOF
|
||||
|
||||
# Commit changes and install the app
|
||||
hood "commit %uniswap"
|
||||
hood "install our %uniswap"
|
||||
|
||||
echo "Uniswap app installed"
|
||||
@@ -0,0 +1,110 @@
|
||||
#!/bin/bash
|
||||
|
||||
# $1: Glob file URL (eg. https://xyz.com/glob-0vabcd.glob)
|
||||
# $2: Glob file hash (eg. 0vabcd)
|
||||
# $3: Urbit ship's pier dir (default: ./zod)
|
||||
|
||||
if [ "$#" -lt 2 ]; then
|
||||
echo "Insufficient arguments"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
glob_url=$1
|
||||
glob_hash=$2
|
||||
echo "Using glob file from ${glob_url} with hash ${glob_hash}"
|
||||
|
||||
# Default pier dir: ./zod
|
||||
# Default desk dir: ./zod/uniswap
|
||||
pier_dir="${3:-./zod}"
|
||||
uniswap_desk_dir="${pier_dir}/uniswap"
|
||||
echo "Using ${uniswap_desk_dir} as the Uniswap desk dir path"
|
||||
|
||||
# Fire curl requests to perform operations on the ship
|
||||
dojo () {
|
||||
curl -s --data '{"source":{"dojo":"'"$1"'"},"sink":{"stdout":null}}' http://localhost:12321
|
||||
}
|
||||
|
||||
hood () {
|
||||
curl -s --data '{"source":{"dojo":"+hood/'"$1"'"},"sink":{"app":"hood"}}' http://localhost:12321
|
||||
}
|
||||
|
||||
# Create/mount a uniswap desk
|
||||
hood "merge %uniswap our %landscape"
|
||||
hood "mount %uniswap"
|
||||
|
||||
# Create a mark file for .map file type
|
||||
cat << EOF > "${uniswap_desk_dir}/mar/map.hoon"
|
||||
::
|
||||
:::: /hoon/map/mar
|
||||
:: Mark for js source maps
|
||||
/? 310
|
||||
::
|
||||
=, eyre
|
||||
|_ mud=@
|
||||
++ grow
|
||||
|%
|
||||
++ mime [/application/octet-stream (as-octs:mimes:html (@t mud))]
|
||||
--
|
||||
++ grab
|
||||
|% :: convert from
|
||||
++ mime |=([p=mite q=octs] (@t q.q))
|
||||
++ noun cord :: clam from %noun
|
||||
--
|
||||
++ grad %mime
|
||||
--
|
||||
EOF
|
||||
|
||||
# Create a mark file for .woff file type
|
||||
cat << EOF > "${uniswap_desk_dir}/mar/woff.hoon"
|
||||
|_ dat=octs
|
||||
++ grow
|
||||
|%
|
||||
++ mime [/font/woff dat]
|
||||
--
|
||||
++ grab
|
||||
|%
|
||||
++ mime |=([=mite =octs] octs)
|
||||
++ noun octs
|
||||
--
|
||||
++ grad %mime
|
||||
--
|
||||
EOF
|
||||
|
||||
# Create a mark file for .ttf file type
|
||||
cat << EOF > "${uniswap_desk_dir}/mar/ttf.hoon"
|
||||
|_ dat=octs
|
||||
++ grow
|
||||
|%
|
||||
++ mime [/font/ttf dat]
|
||||
--
|
||||
++ grab
|
||||
|%
|
||||
++ mime |=([=mite =octs] octs)
|
||||
++ noun octs
|
||||
--
|
||||
++ grad %mime
|
||||
--
|
||||
EOF
|
||||
|
||||
rm "${uniswap_desk_dir}/desk.bill"
|
||||
rm "${uniswap_desk_dir}/desk.ship"
|
||||
|
||||
# Update the docket file
|
||||
cat << EOF > "${uniswap_desk_dir}/desk.docket-0"
|
||||
:~ title+'Uniswap'
|
||||
info+'Self-hosted uniswap frontend.'
|
||||
color+0xcd.75df
|
||||
image+'https://logowik.com/content/uploads/images/uniswap-uni7403.jpg'
|
||||
base+'uniswap'
|
||||
glob-http+['${glob_url}' ${glob_hash}]
|
||||
version+[0 0 1]
|
||||
website+'https://uniswap.org/'
|
||||
license+'MIT'
|
||||
==
|
||||
EOF
|
||||
|
||||
# Commit changes and install the app
|
||||
hood "commit %uniswap"
|
||||
hood "install our %uniswap"
|
||||
|
||||
echo "Uniswap app installed"
|
||||
@@ -0,0 +1,21 @@
|
||||
#!/bin/bash
|
||||
|
||||
# $1: Remote user host
|
||||
# $2: Remote Urbit ship's pier dir path (eg. /home/user/zod)
|
||||
# $3: Glob file URL (eg. https://xyz.com/glob-0vabcd.glob)
|
||||
# $4: Glob file hash (eg. 0vabcd)
|
||||
|
||||
if [ "$#" -ne 4 ]; then
|
||||
echo "Incorrect number of arguments"
|
||||
echo "Usage: $0 <username@remote_host> </path/to/remote/pier/folder> <glob_url> <glob_hash>"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
remote_user_host="$1"
|
||||
remote_pier_folder="$2"
|
||||
glob_url="$3"
|
||||
glob_hash="$4"
|
||||
|
||||
installation_script="./install-uniswap-app.sh"
|
||||
|
||||
ssh "$remote_user_host" "bash -s $glob_url $glob_hash $remote_pier_folder" < "$installation_script"
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
if [ -n "$CERC_SCRIPT_DEBUG" ]; then
|
||||
set -x
|
||||
fi
|
||||
|
||||
pier_dir="/urbit/zod"
|
||||
|
||||
# Run urbit ship in daemon mode
|
||||
# Check if the directory exists
|
||||
if [ -d "$pier_dir" ]; then
|
||||
echo "Pier directory already exists, rebooting..."
|
||||
urbit -d zod
|
||||
else
|
||||
echo "Creating a new fake ship..."
|
||||
urbit -d -F zod
|
||||
fi
|
||||
@@ -0,0 +1,10 @@
|
||||
FROM node:18.17.1-alpine3.18
|
||||
|
||||
RUN apk --update --no-cache add git make alpine-sdk bash
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
COPY . .
|
||||
|
||||
RUN echo "Building uniswap-interface" && \
|
||||
yarn
|
||||
@@ -0,0 +1,8 @@
|
||||
#!/usr/bin/env bash
|
||||
# Build the uniswap-interface image
|
||||
source ${CERC_CONTAINER_BASE_DIR}/build-base.sh
|
||||
|
||||
# See: https://stackoverflow.com/a/246128/1701505
|
||||
SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
|
||||
|
||||
docker build -t cerc/uniswap-interface:local -f ${SCRIPT_DIR}/Dockerfile ${build_command_args} ${CERC_REPO_BASE_DIR}/uniswap-interface
|
||||
@@ -0,0 +1,7 @@
|
||||
FROM python:3.13.0a2-alpine3.18
|
||||
|
||||
RUN apk --update --no-cache add alpine-sdk jq bash curl wget
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
ENTRYPOINT [ "bash" ]
|
||||
@@ -0,0 +1,9 @@
|
||||
#!/usr/bin/env bash
|
||||
# Build the urbit-globs-host image
|
||||
|
||||
source ${CERC_CONTAINER_BASE_DIR}/build-base.sh
|
||||
|
||||
# See: https://stackoverflow.com/a/246128/1701505
|
||||
SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
|
||||
|
||||
docker build -t cerc/urbit-globs-host:local -f ${SCRIPT_DIR}/Dockerfile ${build_command_args} ${SCRIPT_DIR}
|
||||
@@ -59,3 +59,4 @@ cerc/ponder
|
||||
cerc/nitro-rpc-client
|
||||
cerc/watcher-merkl-sushiswap-v3
|
||||
cerc/watcher-sushiswap-v3
|
||||
cerc/uniswap-interface
|
||||
|
||||
@@ -49,3 +49,4 @@ github.com/cerc-io/mobymask-snap
|
||||
github.com/cerc-io/ponder
|
||||
github.com/cerc-io/merkl-sushiswap-v3-watcher-ts
|
||||
github.com/cerc-io/sushiswap-v3-watcher-ts
|
||||
github.com/cerc-io/uniswap-interface
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
# Proxy Server
|
||||
|
||||
Instructions to setup and deploy a HTTP proxy server
|
||||
|
||||
## Setup
|
||||
|
||||
Clone required repository:
|
||||
|
||||
```bash
|
||||
laconic-so --stack proxy-server setup-repositories --pull
|
||||
|
||||
# If this throws an error as a result of being already checked out to a branch/tag in a repo, remove the repositories mentioned below and re-run the command
|
||||
```
|
||||
|
||||
Build the container image:
|
||||
|
||||
```bash
|
||||
laconic-so --stack proxy-server build-containers
|
||||
```
|
||||
|
||||
## Create a deployment
|
||||
|
||||
* First, create a spec file for the deployment, which will allow mapping the stack's ports and volumes to the host:
|
||||
|
||||
```bash
|
||||
laconic-so --stack proxy-server deploy init --output proxy-server-spec.yml
|
||||
```
|
||||
|
||||
* Edit `network` in spec file to map container ports to same ports in host:
|
||||
|
||||
```yml
|
||||
...
|
||||
network:
|
||||
ports:
|
||||
proxy-server:
|
||||
- '4000:4000'
|
||||
...
|
||||
```
|
||||
|
||||
* Once you've made any needed changes to the spec file, create a deployment from it:
|
||||
|
||||
```bash
|
||||
laconic-so --stack proxy-server deploy create --spec-file proxy-server-spec.yml --deployment-dir proxy-server-deployment
|
||||
```
|
||||
|
||||
* Inside the deployment directory, open the file `config.env` and set the following env variables:
|
||||
|
||||
```bash
|
||||
# Whether to run the proxy server (Optional) (Default: true)
|
||||
ENABLE_PROXY=
|
||||
|
||||
# Upstream endpoint
|
||||
# (Eg. https://api.example.org)
|
||||
CERC_PROXY_UPSTREAM=
|
||||
|
||||
# Origin header to be used (Optional)
|
||||
# (Eg. https://app.example.org)
|
||||
CERC_PROXY_ORIGIN_HEADER=
|
||||
```
|
||||
|
||||
## Start the stack
|
||||
|
||||
Start the deployment:
|
||||
|
||||
```bash
|
||||
laconic-so deployment --dir proxy-server-deployment start
|
||||
```
|
||||
|
||||
* List and check the health status of the container using `docker ps`
|
||||
|
||||
* The proxy server will now be listening at http://localhost:4000
|
||||
|
||||
## Clean up
|
||||
|
||||
To stop the service running in background:
|
||||
|
||||
```bash
|
||||
laconic-so deployment --dir proxy-server-deployment stop
|
||||
```
|
||||
@@ -0,0 +1,8 @@
|
||||
version: "0.1"
|
||||
name: proxy-server
|
||||
repos:
|
||||
- github.com/cerc-io/watcher-ts@v0.2.78
|
||||
containers:
|
||||
- cerc/watcher-ts
|
||||
pods:
|
||||
- proxy-server
|
||||
@@ -0,0 +1,151 @@
|
||||
# Self-hosted Uniswap Frontend
|
||||
|
||||
Instructions to setup and deploy Uniswap app on Urbit
|
||||
|
||||
Build and deploy:
|
||||
|
||||
- Urbit
|
||||
- Uniswap app
|
||||
|
||||
## Setup
|
||||
|
||||
Clone required repositories:
|
||||
|
||||
```bash
|
||||
laconic-so --stack uniswap-urbit-app setup-repositories --pull
|
||||
|
||||
# If this throws an error as a result of being already checked out to a branch/tag in a repo, remove the repositories mentioned below and re-run the command
|
||||
```
|
||||
|
||||
Build the container images:
|
||||
|
||||
```bash
|
||||
laconic-so --stack uniswap-urbit-app build-containers
|
||||
```
|
||||
|
||||
## Create a deployment
|
||||
|
||||
First, create a spec file for the deployment, which will map the stack's ports and volumes to the host:
|
||||
|
||||
```bash
|
||||
laconic-so --stack uniswap-urbit-app deploy init --output uniswap-urbit-app-spec.yml
|
||||
```
|
||||
|
||||
### Ports
|
||||
|
||||
Edit `network` in spec file to map container ports to same ports in host
|
||||
|
||||
```
|
||||
...
|
||||
network:
|
||||
ports:
|
||||
urbit-fake-ship:
|
||||
- '8080:80'
|
||||
proxy-server:
|
||||
- '4000:4000'
|
||||
ipfs-glob-host:
|
||||
- '8081:8080'
|
||||
- '5001:5001'
|
||||
...
|
||||
```
|
||||
|
||||
### Data volumes
|
||||
|
||||
Container data volumes are bind-mounted to specified paths in the host filesystem.
|
||||
The default setup (generated by `laconic-so deploy init`) places the volumes in the `./data` subdirectory of the deployment directory. The default mappings can be customized by editing the "spec" file generated by `laconic-so deploy init`.
|
||||
|
||||
---
|
||||
|
||||
Once you've made any needed changes to the spec file, create a deployment from it:
|
||||
|
||||
```bash
|
||||
laconic-so --stack uniswap-urbit-app deploy create --spec-file uniswap-urbit-app-spec.yml --deployment-dir uniswap-urbit-app-deployment
|
||||
```
|
||||
|
||||
## Set env variables
|
||||
|
||||
Inside the deployment directory, open the file `config.env` and set the following env variables:
|
||||
|
||||
```bash
|
||||
# External RPC endpoints
|
||||
# https://docs.infura.io/getting-started#2-create-an-api-key
|
||||
CERC_INFURA_KEY=
|
||||
|
||||
# Uniswap API GQL Endpoint
|
||||
# Set this to GQL proxy server endpoint for uniswap app
|
||||
# (Eg. http://localhost:4000/v1/graphql)
|
||||
# (Eg. https://abc.xyz.com/v1/graphql)
|
||||
CERC_UNISWAP_GQL=
|
||||
|
||||
# Optional
|
||||
|
||||
# Whether to run the proxy GQL server
|
||||
# (Disable only if proxy not required to be run) (Default: true)
|
||||
ENABLE_PROXY=
|
||||
|
||||
# Proxy server configuration
|
||||
# Used only if proxy is enabled
|
||||
|
||||
# Upstream API URL
|
||||
# (Eg. https://api.example.org)
|
||||
CERC_PROXY_UPSTREAM=https://api.uniswap.org
|
||||
|
||||
# Origin header to be used in the proxy
|
||||
# (Eg. https://app.example.org)
|
||||
CERC_PROXY_ORIGIN_HEADER=https://app.uniswap.org
|
||||
|
||||
# IPFS configuration
|
||||
|
||||
# IFPS endpoint to host the glob file on
|
||||
# (Default: http://ipfs-glob-host:5001 pointing to in-stack IPFS node)
|
||||
CERC_IPFS_GLOB_HOST_ENDPOINT=
|
||||
|
||||
# IFPS endpoint to fetch the glob file from
|
||||
# (Default: http://ipfs-glob-host:8080 pointing to in-stack IPFS node)
|
||||
CERC_IPFS_SERVER_ENDPOINT=
|
||||
```
|
||||
|
||||
## Start the stack
|
||||
|
||||
Start the deployment:
|
||||
|
||||
```bash
|
||||
laconic-so deployment --dir uniswap-urbit-app-deployment start
|
||||
```
|
||||
|
||||
* List and check the health status of all the containers using `docker ps` and wait for them to be `healthy`
|
||||
|
||||
* Run the following to get login password for Urbit web interface:
|
||||
|
||||
```bash
|
||||
laconic-so deployment --dir uniswap-urbit-app-deployment exec urbit-fake-ship "curl -s --data '{\"source\":{\"dojo\":\"+code\"},\"sink\":{\"stdout\":null}}' http://localhost:12321"
|
||||
|
||||
# Expected output: "<PASSWORD>\n"%
|
||||
```
|
||||
|
||||
* Open the Urbit web UI at http://localhost:8080 and use the `PASSWORD` from previous step to login
|
||||
|
||||
* The uniswap app is not available when starting stack for the first time. Check `urbit-fake-ship` logs to see that app has installed
|
||||
```
|
||||
laconic-so deployment --dir uniswap-urbit-app-deployment logs -f
|
||||
|
||||
# Expected output:
|
||||
# laconic-3ccf7ee79bdae874-urbit-fake-ship-1 | docket: fetching %http glob for %uniswap desk
|
||||
# laconic-3ccf7ee79bdae874-urbit-fake-ship-1 | ">="">="Uniswap app installed
|
||||
```
|
||||
|
||||
* The uniswap app will be now visible at http://localhost:8080
|
||||
|
||||
## Clean up
|
||||
|
||||
To stop all uniswap-urbit-app services running in the background, while preserving data:
|
||||
|
||||
```bash
|
||||
laconic-so deployment --dir uniswap-urbit-app-deployment stop
|
||||
```
|
||||
|
||||
To stop all uniswap-urbit-app services and also delete data:
|
||||
|
||||
```bash
|
||||
laconic-so deployment --dir uniswap-urbit-app-deployment stop --delete-volumes
|
||||
```
|
||||
@@ -0,0 +1,13 @@
|
||||
version: "0.1"
|
||||
name: uniswap-urbit-app
|
||||
repos:
|
||||
- github.com/cerc-io/uniswap-interface@laconic # TODO: Use release
|
||||
- github.com/cerc-io/watcher-ts@v0.2.78
|
||||
containers:
|
||||
- cerc/uniswap-interface
|
||||
- cerc/watcher-ts
|
||||
- cerc/urbit-globs-host
|
||||
pods:
|
||||
- uniswap-interface
|
||||
- proxy-server
|
||||
- uniswap-urbit
|
||||
@@ -24,6 +24,8 @@ from importlib import resources
|
||||
import subprocess
|
||||
import click
|
||||
from pathlib import Path
|
||||
from stack_orchestrator import constants
|
||||
from stack_orchestrator.opts import opts
|
||||
from stack_orchestrator.util import include_exclude_check, get_parsed_stack_config, global_options2, get_dev_root_path
|
||||
from stack_orchestrator.deploy.deployer import Deployer, DeployerException
|
||||
from stack_orchestrator.deploy.deployer_factory import getDeployer
|
||||
@@ -70,6 +72,9 @@ def create_deploy_context(
|
||||
cluster,
|
||||
env_file,
|
||||
deploy_to) -> DeployCommandContext:
|
||||
# Extract the cluster name from the deployment, if we have one
|
||||
if deployment_context and cluster is None:
|
||||
cluster = deployment_context.get_cluster_id()
|
||||
cluster_context = _make_cluster_context(global_context, stack, include, exclude, cluster, env_file)
|
||||
deployer = getDeployer(deploy_to, deployment_context, compose_files=cluster_context.compose_files,
|
||||
compose_project_name=cluster_context.cluster,
|
||||
@@ -253,6 +258,22 @@ def _make_runtime_env(ctx):
|
||||
return container_exec_env
|
||||
|
||||
|
||||
def _make_default_cluster_name(deployment, compose_dir, stack, include, exclude):
|
||||
# Create default unique, stable cluster name from confile file path and stack name if provided
|
||||
if deployment:
|
||||
path = os.path.realpath(os.path.abspath(compose_dir))
|
||||
else:
|
||||
path = "internal"
|
||||
unique_cluster_descriptor = f"{path},{stack},{include},{exclude}"
|
||||
if opts.o.debug:
|
||||
print(f"pre-hash descriptor: {unique_cluster_descriptor}")
|
||||
hash = hashlib.md5(unique_cluster_descriptor.encode()).hexdigest()[:16]
|
||||
cluster = f"{constants.cluster_name_prefix}{hash}"
|
||||
if opts.o.debug:
|
||||
print(f"Using cluster name: {cluster}")
|
||||
return cluster
|
||||
|
||||
|
||||
# stack has to be either PathLike pointing to a stack yml file, or a string with the name of a known stack
|
||||
def _make_cluster_context(ctx, stack, include, exclude, cluster, env_file):
|
||||
|
||||
@@ -270,16 +291,9 @@ def _make_cluster_context(ctx, stack, include, exclude, cluster, env_file):
|
||||
compose_dir = Path(__file__).absolute().parent.parent.joinpath("data", "compose")
|
||||
|
||||
if cluster is None:
|
||||
# Create default unique, stable cluster name from confile file path and stack name if provided
|
||||
# TODO: change this to the config file path
|
||||
path = os.path.realpath(sys.argv[0])
|
||||
unique_cluster_descriptor = f"{path},{stack},{include},{exclude}"
|
||||
if ctx.debug:
|
||||
print(f"pre-hash descriptor: {unique_cluster_descriptor}")
|
||||
hash = hashlib.md5(unique_cluster_descriptor.encode()).hexdigest()[:16]
|
||||
cluster = f"laconic-{hash}"
|
||||
if ctx.verbose:
|
||||
print(f"Using cluster name: {cluster}")
|
||||
cluster = _make_default_cluster_name(deployment, compose_dir, stack, include, exclude)
|
||||
else:
|
||||
_make_default_cluster_name(deployment, compose_dir, stack, include, exclude)
|
||||
|
||||
# See: https://stackoverflow.com/a/20885799/1701505
|
||||
from stack_orchestrator import data
|
||||
|
||||
@@ -52,7 +52,7 @@ def make_deploy_context(ctx) -> DeployCommandContext:
|
||||
context: DeploymentContext = ctx.obj
|
||||
stack_file_path = context.get_stack_file()
|
||||
env_file = context.get_env_file()
|
||||
cluster_name = context.get_cluster_name()
|
||||
cluster_name = context.get_cluster_id()
|
||||
if constants.deploy_to_key in context.spec.obj:
|
||||
deployment_type = context.spec.obj[constants.deploy_to_key]
|
||||
else:
|
||||
|
||||
@@ -14,15 +14,19 @@
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http:#www.gnu.org/licenses/>.
|
||||
|
||||
import hashlib
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
from stack_orchestrator import constants
|
||||
from stack_orchestrator.util import get_yaml
|
||||
from stack_orchestrator.deploy.stack import Stack
|
||||
from stack_orchestrator.deploy.spec import Spec
|
||||
|
||||
|
||||
class DeploymentContext:
|
||||
deployment_dir: Path
|
||||
id: str
|
||||
spec: Spec
|
||||
stack: Stack
|
||||
|
||||
@@ -35,9 +39,14 @@ class DeploymentContext:
|
||||
def get_env_file(self):
|
||||
return self.deployment_dir.joinpath(constants.config_file_name)
|
||||
|
||||
# TODO: implement me
|
||||
def get_cluster_name(self):
|
||||
return None
|
||||
def get_deployment_file(self):
|
||||
return self.deployment_dir.joinpath(constants.deployment_file_name)
|
||||
|
||||
def get_compose_dir(self):
|
||||
return self.deployment_dir.joinpath(constants.compose_dir_name)
|
||||
|
||||
def get_cluster_id(self):
|
||||
return self.id
|
||||
|
||||
def init(self, dir):
|
||||
self.deployment_dir = dir
|
||||
@@ -45,3 +54,16 @@ class DeploymentContext:
|
||||
self.spec.init_from_file(self.get_spec_file())
|
||||
self.stack = Stack(self.spec.obj["stack"])
|
||||
self.stack.init_from_file(self.get_stack_file())
|
||||
deployment_file_path = self.get_deployment_file()
|
||||
if deployment_file_path.exists():
|
||||
with deployment_file_path:
|
||||
obj = get_yaml().load(open(deployment_file_path, "r"))
|
||||
self.id = obj[constants.cluster_id_key]
|
||||
# Handle the case of a legacy deployment with no file
|
||||
# Code below is intended to match the output from _make_default_cluster_name()
|
||||
# TODO: remove when we no longer need to support legacy deployments
|
||||
else:
|
||||
path = os.path.realpath(os.path.abspath(self.get_compose_dir()))
|
||||
unique_cluster_descriptor = f"{path},{self.get_stack_file()},None,None"
|
||||
hash = hashlib.md5(unique_cluster_descriptor.encode()).hexdigest()[:16]
|
||||
self.id = f"{constants.cluster_name_prefix}{hash}"
|
||||
|
||||
@@ -20,6 +20,7 @@ from pathlib import Path
|
||||
from typing import List
|
||||
import random
|
||||
from shutil import copy, copyfile, copytree
|
||||
from secrets import token_hex
|
||||
import sys
|
||||
from stack_orchestrator import constants
|
||||
from stack_orchestrator.opts import opts
|
||||
@@ -276,7 +277,7 @@ def init(ctx, config, config_file, kube_config, image_registry, output, map_port
|
||||
# call it from other commands, bypassing the click decoration stuff
|
||||
def init_operation(deploy_command_context, stack, deployer_type, config,
|
||||
config_file, kube_config, image_registry, output, map_ports_to_host):
|
||||
yaml = get_yaml()
|
||||
|
||||
default_spec_file_content = call_stack_deploy_init(deploy_command_context)
|
||||
spec_file_content = {"stack": stack, constants.deploy_to_key: deployer_type}
|
||||
if deployer_type == "k8s":
|
||||
@@ -311,8 +312,6 @@ def init_operation(deploy_command_context, stack, deployer_type, config,
|
||||
new_config = config_file_variables
|
||||
merged_config = {**new_config, **orig_config}
|
||||
spec_file_content.update({"config": merged_config})
|
||||
if opts.o.debug:
|
||||
print(f"Creating spec file for stack: {stack} with content: {spec_file_content}")
|
||||
|
||||
ports = _get_mapped_ports(stack, map_ports_to_host)
|
||||
spec_file_content.update({"network": {"ports": ports}})
|
||||
@@ -324,8 +323,11 @@ def init_operation(deploy_command_context, stack, deployer_type, config,
|
||||
volume_descriptors[named_volume] = f"./data/{named_volume}"
|
||||
spec_file_content["volumes"] = volume_descriptors
|
||||
|
||||
if opts.o.debug:
|
||||
print(f"Creating spec file for stack: {stack} with content: {spec_file_content}")
|
||||
|
||||
with open(output, "w") as output_file:
|
||||
yaml.dump(spec_file_content, output_file)
|
||||
get_yaml().dump(spec_file_content, output_file)
|
||||
|
||||
|
||||
def _write_config_file(spec_file: Path, config_env_file: Path):
|
||||
@@ -351,6 +353,13 @@ def _copy_files_to_directory(file_paths: List[Path], directory: Path):
|
||||
copy(path, os.path.join(directory, os.path.basename(path)))
|
||||
|
||||
|
||||
def _create_deployment_file(deployment_dir: Path):
|
||||
deployment_file_path = deployment_dir.joinpath(constants.deployment_file_name)
|
||||
cluster = f"{constants.cluster_name_prefix}{token_hex(8)}"
|
||||
with open(deployment_file_path, "w") as output_file:
|
||||
output_file.write(f"{constants.cluster_id_key}: {cluster}\n")
|
||||
|
||||
|
||||
@click.command()
|
||||
@click.option("--spec-file", required=True, help="Spec file to use to create this deployment")
|
||||
@click.option("--deployment-dir", help="Create deployment files in this directory")
|
||||
@@ -383,6 +392,7 @@ def create_operation(deployment_command_context, spec_file, deployment_dir, netw
|
||||
# Copy spec file and the stack file into the deployment dir
|
||||
copyfile(spec_file, deployment_dir_path.joinpath(constants.spec_file_name))
|
||||
copyfile(stack_file, deployment_dir_path.joinpath(os.path.basename(stack_file)))
|
||||
_create_deployment_file(deployment_dir_path)
|
||||
# Copy any config varibles from the spec file into an env file suitable for compose
|
||||
_write_config_file(spec_file, deployment_dir_path.joinpath(constants.config_file_name))
|
||||
# Copy any k8s config file into the deployment dir
|
||||
|
||||
Reference in New Issue
Block a user