Compare commits

..
Author SHA1 Message Date
dboreham faa48e8ca8 Merge branch 'main' into dboreham/laconicd-k8s 2024-02-06 12:32:41 -07:00
dboreham 037ffe9a47 Merge branch 'main' into dboreham/laconicd-k8s 2024-02-06 12:00:44 -07:00
dboreham 01ab438c7e Merge main 2024-02-06 07:11:08 -07:00
dboreham c85f31760d Merge main 2024-02-05 06:47:13 -07:00
dboreham f67668c1be Fix lint error 2024-01-30 06:51:03 -07:00
dboreham 2c17b901a8 Fix volume parsing 2024-01-28 22:14:18 -07:00
dboreham 886f1f322c Fix template filename 2024-01-28 22:01:51 -07:00
dboreham d279aedf84 Changes for fixturenet-laconic-loaded in k8s 2024-01-28 21:57:01 -07:00
106 changed files with 445 additions and 3434 deletions
-21
View File
@@ -1,21 +0,0 @@
name: Lint Checks
on:
pull_request:
branches: '*'
push:
branches: '*'
jobs:
test:
name: "Run linter"
runs-on: ubuntu-latest
steps:
- name: "Clone project repository"
uses: actions/checkout@v3
- name: "Install Python"
uses: actions/setup-python@v4
with:
python-version: '3.8'
- name : "Run flake8"
uses: py-actions/flake8@v2
@@ -1,54 +0,0 @@
name: Container Registry Test
on:
push:
branches: '*'
paths:
- '!**'
- '.gitea/workflows/triggers/test-container-registry'
- '.gitea/workflows/test-container-registry.yml'
- 'tests/container-registry/run-test.sh'
schedule: # Note: coordinate with other tests to not overload runners at the same time of day
- cron: '6 19 * * *'
jobs:
test:
name: "Run contaier registry hosting test on kind/k8s"
runs-on: ubuntu-22.04
steps:
- name: "Clone project repository"
uses: actions/checkout@v3
# At present the stock setup-python action fails on Linux/aarch64
# Conditional steps below workaroud this by using deadsnakes for that case only
- name: "Install Python for ARM on Linux"
if: ${{ runner.arch == 'arm64' && runner.os == 'Linux' }}
uses: deadsnakes/action@v3.0.1
with:
python-version: '3.8'
- name: "Install Python cases other than ARM on Linux"
if: ${{ ! (runner.arch == 'arm64' && runner.os == 'Linux') }}
uses: actions/setup-python@v4
with:
python-version: '3.8'
- name: "Print Python version"
run: python3 --version
- name: "Install shiv"
run: pip install shiv
- name: "Generate build version file"
run: ./scripts/create_build_tag_file.sh
- name: "Build local shiv package"
run: ./scripts/build_shiv_package.sh
- name: "Check cgroups version"
run: mount | grep cgroup
- name: "Install kind"
run: ./tests/scripts/install-kind.sh
- name: "Install Kubectl"
run: ./tests/scripts/install-kubectl.sh
- name: "Install ed" # Only needed until we remove the need to edit the spec file
run: apt update && apt install -y ed
- name: "Run container registry deployment test"
run: |
source /opt/bash-utils/cgroup-helper.sh
join_cgroup
./tests/container-registry/run-test.sh
-52
View File
@@ -1,52 +0,0 @@
name: Database Test
on:
push:
branches: '*'
paths:
- '!**'
- '.gitea/workflows/triggers/test-database'
- '.gitea/workflows/test-database.yml'
- 'tests/database/run-test.sh'
schedule: # Note: coordinate with other tests to not overload runners at the same time of day
- cron: '5 18 * * *'
jobs:
test:
name: "Run database hosting test on kind/k8s"
runs-on: ubuntu-22.04
steps:
- name: "Clone project repository"
uses: actions/checkout@v3
# At present the stock setup-python action fails on Linux/aarch64
# Conditional steps below workaroud this by using deadsnakes for that case only
- name: "Install Python for ARM on Linux"
if: ${{ runner.arch == 'arm64' && runner.os == 'Linux' }}
uses: deadsnakes/action@v3.0.1
with:
python-version: '3.8'
- name: "Install Python cases other than ARM on Linux"
if: ${{ ! (runner.arch == 'arm64' && runner.os == 'Linux') }}
uses: actions/setup-python@v4
with:
python-version: '3.8'
- name: "Print Python version"
run: python3 --version
- name: "Install shiv"
run: pip install shiv
- name: "Generate build version file"
run: ./scripts/create_build_tag_file.sh
- name: "Build local shiv package"
run: ./scripts/build_shiv_package.sh
- name: "Check cgroups version"
run: mount | grep cgroup
- name: "Install kind"
run: ./tests/scripts/install-kind.sh
- name: "Install Kubectl"
run: ./tests/scripts/install-kubectl.sh
- name: "Run database deployment test"
run: |
source /opt/bash-utils/cgroup-helper.sh
join_cgroup
./tests/database/run-test.sh
-2
View File
@@ -1,8 +1,6 @@
name: K8s Deploy Test
on:
pull_request:
branches: '*'
push:
branches: '*'
paths:
@@ -1 +0,0 @@
Change this file to trigger running the test-container-registry CI job
-2
View File
@@ -1,2 +0,0 @@
Change this file to trigger running the test-database CI job
Trigger test run
+3 -3
View File
@@ -29,10 +29,10 @@ chmod +x ~/.docker/cli-plugins/docker-compose
Next decide on a directory where you would like to put the stack-orchestrator program. Typically this would be
a "user" binary directory such as `~/bin` or perhaps `/usr/local/laconic` or possibly just the current working directory.
Now, having selected that directory, download the latest release from [this page](https://git.vdb.to/cerc-io/stack-orchestrator/tags) into it (we're using `~/bin` below for concreteness but edit to suit if you selected a different directory). Also be sure that the destination directory exists and is writable:
Now, having selected that directory, download the latest release from [this page](https://github.com/cerc-io/stack-orchestrator/tags) into it (we're using `~/bin` below for concreteness but edit to suit if you selected a different directory). Also be sure that the destination directory exists and is writable:
```bash
curl -L -o ~/bin/laconic-so https://git.vdb.to/cerc-io/stack-orchestrator/releases/download/latest/laconic-so
curl -L -o ~/bin/laconic-so https://github.com/cerc-io/stack-orchestrator/releases/latest/download/laconic-so
```
Give it execute permissions:
@@ -52,7 +52,7 @@ Version: 1.1.0-7a607c2-202304260513
Save the distribution url to `~/.laconic-so/config.yml`:
```bash
mkdir ~/.laconic-so
echo "distribution-url: https://git.vdb.to/cerc-io/stack-orchestrator/releases/download/latest/laconic-so" > ~/.laconic-so/config.yml
echo "distribution-url: https://github.com/cerc-io/stack-orchestrator/releases/latest/download/laconic-so" > ~/.laconic-so/config.yml
```
### Update
+1 -1
View File
@@ -26,7 +26,7 @@ In addition to the pre-requisites listed in the [README](/README.md), the follow
1. Clone this repository:
```
$ git clone https://git.vdb.to/cerc-io/stack-orchestrator.git
$ git clone https://github.com/cerc-io/stack-orchestrator.git
```
2. Enter the project directory:
+2 -2
View File
@@ -1,10 +1,10 @@
# Adding a new stack
See [this PR](https://git.vdb.to/cerc-io/stack-orchestrator/pull/434) for an example of how to currently add a minimal stack to stack orchestrator. The [reth stack](https://git.vdb.to/cerc-io/stack-orchestrator/pull/435) is another good example.
See [this PR](https://github.com/cerc-io/stack-orchestrator/pull/434) for an example of how to currently add a minimal stack to stack orchestrator. The [reth stack](https://github.com/cerc-io/stack-orchestrator/pull/435) is another good example.
For external developers, we recommend forking this repo and adding your stack directly to your fork. This initially requires running in "developer mode" as described [here](/docs/CONTRIBUTING.md). Check out the [Namada stack](https://github.com/vknowable/stack-orchestrator/blob/main/app/data/stacks/public-namada/digitalocean_quickstart.md) from Knowable to see how that is done.
Core to the feature completeness of stack orchestrator is to [decouple the tool functionality from payload](https://git.vdb.to/cerc-io/stack-orchestrator/issues/315) which will no longer require forking to add a stack.
Core to the feature completeness of stack orchestrator is to [decouple the tool functionality from payload](https://github.com/cerc-io/stack-orchestrator/issues/315) which will no longer require forking to add a stack.
## Example
+1 -1
View File
@@ -1,6 +1,6 @@
# Specification
Note: this page is out of date (but still useful) - it will no longer be useful once stacks are [decoupled from the tool functionality](https://git.vdb.to/cerc-io/stack-orchestrator/issues/315).
Note: this page is out of date (but still useful) - it will no longer be useful once stacks are [decoupled from the tool functionality](https://github.com/cerc-io/stack-orchestrator/issues/315).
## Implementation
-1
View File
@@ -10,4 +10,3 @@ pydantic==1.10.9
tomli==2.0.1
validators==0.22.0
kubernetes>=28.1.0
humanfriendly>=10.0
+1 -1
View File
@@ -41,4 +41,4 @@ runcmd:
- apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
- systemctl enable docker
- systemctl start docker
- git clone https://git.vdb.to/cerc-io/stack-orchestrator.git /home/ubuntu/stack-orchestrator
- git clone https://github.com/cerc-io/stack-orchestrator.git /home/ubuntu/stack-orchestrator
+1 -1
View File
@@ -31,5 +31,5 @@ runcmd:
- apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
- systemctl enable docker
- systemctl start docker
- curl -L -o /usr/local/bin/laconic-so https://git.vdb.to/cerc-io/stack-orchestrator/releases/download/latest/laconic-so
- curl -L -o /usr/local/bin/laconic-so https://github.com/cerc-io/stack-orchestrator/releases/latest/download/laconic-so
- chmod +x /usr/local/bin/laconic-so
-19
View File
@@ -1,19 +0,0 @@
#!/usr/bin/env bash
# Beginnings of a script to quickly spin up and test a deployment
if [[ -n "$CERC_SCRIPT_DEBUG" ]]; then
set -x
fi
if [[ -n "$1" ]]; then
stack_name=$1
else
stack_name="test"
fi
spec_file_name="${stack_name}-spec.yml"
deployment_dir_name="${stack_name}-deployment"
rm -f ${spec_file_name}
rm -rf ${deployment_dir_name}
laconic-so --stack ${stack_name} deploy --deploy-to compose init --output ${spec_file_name}
laconic-so --stack ${stack_name} deploy --deploy-to compose create --deployment-dir ${deployment_dir_name} --spec-file ${spec_file_name}
#laconic-so deployment --dir ${deployment_dir_name} start
#laconic-so deployment --dir ${deployment_dir_name} ps
#laconic-so deployment --dir ${deployment_dir_name} stop
+1 -1
View File
@@ -137,7 +137,7 @@ fi
echo "**************************************************************************************"
echo "Installing laconic-so"
# install latest `laconic-so`
distribution_url=https://git.vdb.to/cerc-io/stack-orchestrator/releases/download/latest/laconic-so
distribution_url=https://github.com/cerc-io/stack-orchestrator/releases/latest/download/laconic-so
install_filename=${install_dir}/laconic-so
mkdir -p ${install_dir}
curl -L -o ${install_filename} ${distribution_url}
+1 -1
View File
@@ -13,7 +13,7 @@ setup(
description='Orchestrates deployment of the Laconic stack',
long_description=long_description,
long_description_content_type="text/markdown",
url='https://git.vdb.to/cerc-io/stack-orchestrator',
url='https://github.com/cerc-io/stack-orchestrator',
py_modules=['stack_orchestrator'],
packages=find_packages(),
install_requires=[requirements],
+1 -3
View File
@@ -27,7 +27,7 @@ import subprocess
import click
import importlib.resources
from pathlib import Path
from stack_orchestrator.util import include_exclude_check, get_parsed_stack_config, stack_is_external, warn_exit
from stack_orchestrator.util import include_exclude_check, get_parsed_stack_config, stack_is_external
from stack_orchestrator.base import get_npm_registry_url
# TODO: find a place for this
@@ -164,8 +164,6 @@ def command(ctx, include, exclude, force_rebuild, extra_build_args):
containers_in_scope = []
if stack:
stack_config = get_parsed_stack_config(stack)
if "containers" not in stack_config or stack_config["containers"] is None:
warn_exit(f"stack {stack} does not define any containers")
containers_in_scope = stack_config['containers']
else:
containers_in_scope = all_containers
+1 -7
View File
@@ -27,12 +27,6 @@ kube_config_key = "kube-config"
deploy_to_key = "deploy-to"
network_key = "network"
http_proxy_key = "http-proxy"
image_registry_key = "image-registry"
configmaps_key = "configmaps"
resources_key = "resources"
volumes_key = "volumes"
security_key = "security"
annotations_key = "annotations"
labels_key = "labels"
image_resigtry_key = "image-registry"
kind_config_filename = "kind-config.yml"
kube_config_filename = "kubeconfig.yml"
@@ -1,13 +0,0 @@
services:
registry:
image: registry:2.8
restart: always
environment:
REGISTRY_LOG_LEVEL: ${REGISTRY_LOG_LEVEL}
volumes:
- registry-data:/var/lib/registry
ports:
- "5000"
volumes:
registry-data:
@@ -7,9 +7,7 @@ services:
# The cosmos-sdk node's database directory:
- laconicd-data:/root/.laconicd
# TODO: look at folding these scripts into the container
- ../config/fixturenet-laconicd/create-fixturenet.sh:/docker-entrypoint-scripts.d/create-fixturenet.sh
- ../config/fixturenet-laconicd/export-mykey.sh:/docker-entrypoint-scripts.d/export-mykey.sh
- ../config/fixturenet-laconicd/export-myaddress.sh:/docker-entrypoint-scripts.d/export-myaddress.sh
- laconicd-scripts:/docker-entrypoint-scripts.d:ro
# TODO: determine which of the ports below is really needed
ports:
- "6060"
@@ -24,7 +22,9 @@ services:
cli:
image: cerc/laconic-registry-cli:local
volumes:
- ../config/fixturenet-laconicd/registry-cli-config-template.yml:/registry-cli-config-template.yml
- cli-config:/registry-cli-config
volumes:
laconicd-data:
laconicd-scripts:
cli-config:
@@ -9,9 +9,7 @@ services:
- laconicd-config:/root/.laconicd/config
- laconicd-keyring:/root/.laconicd/keyring-test
# TODO: look at folding these scripts into the container
- ../config/mainnet-laconicd/scripts/run-laconicd.sh:/opt/run-laconicd.sh
- ../config/mainnet-laconicd/scripts/export-mykey.sh:/docker-entrypoint-scripts.d/export-mykey.sh
- ../config/mainnet-laconicd/scripts/export-myaddress.sh:/docker-entrypoint-scripts.d/export-myaddress.sh
- laconicd-scripts:/docker-entrypoint-scripts.d:ro
# TODO: determine which of the ports below is really needed
ports:
- "6060"
@@ -26,9 +24,11 @@ services:
cli:
image: cerc/laconic-registry-cli:local
volumes:
- ../config/mainnet-laconicd/registry-cli-config-template.yml:/registry-cli-config-template.yml
- cli-config:/registry-cli-config
volumes:
laconicd-data:
laconicd-config:
laconicd-scripts:
laconicd-keyring:
cli-config:
@@ -1,12 +0,0 @@
version: "3.2"
services:
mars:
image: cerc/mars-v2:local
restart: always
ports:
- "3000:3000"
environment:
- URL_OSMOSIS_REST=https://lcd-osmosis.blockapsis.com
- URL_OSMOSIS_RPC=https://rpc-osmosis.blockapsis.com
- WALLET_CONNECT_ID=0x0x0x0x0x0x0x0x0x0x0x0x0x0x0x0x0x0x0x0x
@@ -1,20 +0,0 @@
version: "3.2"
services:
mars:
image: cerc/mars:local
restart: always
ports:
- "3000:3000"
environment:
- URL_OSMOSIS_GQL=https://osmosis-node.marsprotocol.io/GGSFGSFGFG34/osmosis-hive-front/graphql
- URL_OSMOSIS_REST=https://lcd-osmosis.blockapsis.com
- URL_OSMOSIS_RPC=https://rpc-osmosis.blockapsis.com
- URL_NEUTRON_GQL=https://neutron.rpc.p2p.world/qgrnU6PsQZA8F9S5Fb8Fn3tV3kXmMBl2M9bcc9jWLjQy8p/hive/graphql
- URL_NEUTRON_REST=https://rest-kralum.neutron-1.neutron.org
- URL_NEUTRON_RPC=https://rpc-kralum.neutron-1.neutron.org
- URL_NEUTRON_TEST_GQL=https://testnet-neutron-gql.marsprotocol.io/graphql
- URL_NEUTRON_TEST_REST=https://rest-palvus.pion-1.ntrn.tech
- URL_NEUTRON_TEST_RPC=https://rpc-palvus.pion-1.ntrn.tech
- WALLET_CONNECT_ID=0x0x0x0x0x0x0x0x0x0x0x0x0x0x0x0x0x0x0x0x
@@ -1,32 +0,0 @@
version: '3.2'
services:
# Builds and serves the MobyMask v3 react-app
mobymask-v3-app:
restart: unless-stopped
image: cerc/mobymask-ui:local
environment:
CERC_SCRIPT_DEBUG: ${CERC_SCRIPT_DEBUG}
CERC_APP_WATCHER_URL: ${CERC_APP_WATCHER_URL}
CERC_SNAP_URL: ${CERC_SNAP_URL}
working_dir: /app
command: ["bash", "/scripts/mobymask-app-start.sh"]
volumes:
- ../config/watcher-mobymask-v3-demo/mobymask-app-start.sh:/scripts/mobymask-app-start.sh
- ../config/watcher-mobymask-v3-demo/local/keys:/server/keys
- mobymask_deployment:/server
- nitro_deployment:/nitro
ports:
- "127.0.0.1:3004:80"
healthcheck:
test: ["CMD", "nc", "-vz", "localhost", "80"]
interval: 20s
timeout: 5s
retries: 15
start_period: 10s
extra_hosts:
- "host.docker.internal:host-gateway"
volumes:
mobymask_deployment:
nitro_deployment:
@@ -1,8 +0,0 @@
version: "3.2"
services:
ping-pub:
image: cerc/ping-pub:local
restart: always
ports:
- "5173:5173"
@@ -1,13 +0,0 @@
services:
snowballtools-base-backend:
image: cerc/snowballtools-base-backend:local
restart: always
volumes:
- data:/data
- config:/config:ro
ports:
- 8000
volumes:
data:
config:
@@ -1,20 +0,0 @@
services:
database:
image: cerc/test-database-container:local
restart: always
volumes:
- db-data:/var/lib/postgresql/data
environment:
POSTGRES_USER: "test-user"
POSTGRES_DB: "test-db"
POSTGRES_PASSWORD: "password"
POSTGRES_INITDB_ARGS: "-E UTF8 --locale=C"
ports:
- "5432"
test-client:
image: cerc/test-database-client:local
volumes:
db-data:
@@ -5,15 +5,12 @@ services:
environment:
CERC_SCRIPT_DEBUG: ${CERC_SCRIPT_DEBUG}
CERC_TEST_PARAM_1: ${CERC_TEST_PARAM_1:-FAILED}
CERC_TEST_PARAM_2: "CERC_TEST_PARAM_2_VALUE"
volumes:
- test-data-bind:/data
- test-data-auto:/data2
- test-data:/data
- test-config:/config:ro
ports:
- "80"
volumes:
test-data-bind:
test-data-auto:
test-data:
test-config:
@@ -1,162 +0,0 @@
version: '3.2'
services:
# Starts the PostgreSQL database for watcher
mobymask-watcher-db:
restart: unless-stopped
image: postgres:14-alpine
environment:
- POSTGRES_USER=vdbm
- POSTGRES_MULTIPLE_DATABASES=mobymask-watcher-1,mobymask-watcher-1-job-queue,mobymask-watcher-2,mobymask-watcher-2-job-queue,mobymask-watcher-3,mobymask-watcher-3-job-queue
- POSTGRES_EXTENSION=mobymask-watcher-1-job-queue:pgcrypto,mobymask-watcher-2-job-queue:pgcrypto,mobymask-watcher-3-job-queue:pgcrypto
- POSTGRES_PASSWORD=password
volumes:
- ../config/postgresql/multiple-postgressql-databases.sh:/docker-entrypoint-initdb.d/multiple-postgressql-databases.sh
- mobymask_watcher_db_data:/var/lib/postgresql/data
ports:
- "5432"
healthcheck:
test: ["CMD", "nc", "-v", "localhost", "5432"]
interval: 20s
timeout: 5s
retries: 15
start_period: 10s
# Deploys the MobyMask contract and generates an invite link
# Deployment is skipped if CERC_DEPLOYED_CONTRACT env is set
mobymask:
image: cerc/mobymask:local
working_dir: /app/packages/server
environment:
CERC_SCRIPT_DEBUG: ${CERC_SCRIPT_DEBUG}
# ENV: "PROD" # Check if required
CERC_ETH_RPC_ENDPOINT: ${CERC_ETH_RPC_ENDPOINT}
CERC_PRIVATE_KEY_DEPLOYER: ${CERC_PRIVATE_KEY_DEPLOYER}
CERC_MOBYMASK_APP_BASE_URI: ${CERC_MOBYMASK_APP_BASE_URI}
CERC_DEPLOYED_CONTRACT: ${CERC_DEPLOYED_CONTRACT}
command: ["bash", "-c", "./deploy-and-generate-invite.sh"]
volumes:
- ../config/watcher-mobymask-v3-demo/deploy-and-generate-invite.sh:/app/packages/server/deploy-and-generate-invite.sh
- mobymask_deployment:/app/packages/server
extra_hosts:
- "host.docker.internal:host-gateway"
# Starts a MobyMask v3 watcher server #1
mobymask-watcher-1-server:
image: cerc/watcher-mobymask-v3:local
restart: unless-stopped
depends_on:
mobymask-watcher-db:
condition: service_healthy
mobymask:
condition: service_completed_successfully
nitro-contracts:
condition: service_completed_successfully
environment:
CERC_SCRIPT_DEBUG: ${CERC_SCRIPT_DEBUG}
CERC_WATCHER_INDEX: 1
CERC_ETH_RPC_QUERY_ENDPOINT: ${CERC_ETH_RPC_QUERY_ENDPOINT}
CERC_ETH_RPC_MUTATION_ENDPOINT: ${CERC_ETH_RPC_MUTATION_ENDPOINT}
CERC_NITRO_CHAIN_URL: ${CERC_NITRO_CHAIN_URL}
command: ["bash", "./start-server.sh"]
volumes:
- ../config/watcher-mobymask-v3-demo/watcher-config-template.toml:/app/environments/watcher-config-template.toml
- ../config/watcher-mobymask-v3-demo/watcher-config-rates.toml:/app/environments/rates.toml
- ../config/watcher-mobymask-v3-demo/local/keys:/app/keys
- ../config/watcher-mobymask-v3-demo/start-server.sh:/app/start-server.sh
- watcher_nitro_data:/app/out/nitro-db
- nitro_deployment:/nitro
- mobymask_deployment:/server
# Expose GQL, metrics and relay node ports
ports:
- "0.0.0.0:3001:3001"
- "9001"
- "0.0.0.0:9090:9090"
healthcheck:
test: ["CMD", "busybox", "nc", "localhost", "9090"]
interval: 20s
timeout: 5s
retries: 15
start_period: 5s
extra_hosts:
- "host.docker.internal:host-gateway"
# Starts a MobyMask v3 watcher server #2
mobymask-watcher-2-server:
image: cerc/watcher-mobymask-v3:local
restart: unless-stopped
depends_on:
mobymask-watcher-1-server:
condition: service_healthy
environment:
CERC_SCRIPT_DEBUG: ${CERC_SCRIPT_DEBUG}
CERC_WATCHER_INDEX: 2
CERC_ETH_RPC_QUERY_ENDPOINT: ${CERC_ETH_RPC_QUERY_ENDPOINT}
CERC_ETH_RPC_MUTATION_ENDPOINT: ${CERC_ETH_RPC_MUTATION_ENDPOINT}
CERC_NITRO_CHAIN_URL: ${CERC_NITRO_CHAIN_URL}
command: ["bash", "./start-server.sh"]
volumes:
- ../config/watcher-mobymask-v3-demo/watcher-config-template.toml:/app/environments/watcher-config-template.toml
- ../config/watcher-mobymask-v3-demo/watcher-config-rates.toml:/app/environments/rates.toml
- ../config/watcher-mobymask-v3-demo/local/keys:/app/keys
- ../config/watcher-mobymask-v3-demo/start-server.sh:/app/start-server.sh
- watcher_nitro_data:/app/out/nitro-db
- nitro_deployment:/nitro
- mobymask_deployment:/server
# Expose GQL, metrics and relay node ports
ports:
- "3001"
- "9001"
- "0.0.0.0:9091:9090"
healthcheck:
test: ["CMD", "busybox", "nc", "localhost", "9090"]
interval: 20s
timeout: 5s
retries: 15
start_period: 5s
extra_hosts:
- "host.docker.internal:host-gateway"
# Starts a MobyMask v3 watcher server #3
mobymask-watcher-3-server:
image: cerc/watcher-mobymask-v3:local
restart: unless-stopped
depends_on:
mobymask-watcher-1-server:
condition: service_healthy
mobymask-watcher-2-server:
condition: service_healthy
environment:
CERC_SCRIPT_DEBUG: ${CERC_SCRIPT_DEBUG}
CERC_WATCHER_INDEX: 3
CERC_ETH_RPC_QUERY_ENDPOINT: ${CERC_ETH_RPC_QUERY_ENDPOINT}
CERC_ETH_RPC_MUTATION_ENDPOINT: ${CERC_ETH_RPC_MUTATION_ENDPOINT}
CERC_NITRO_CHAIN_URL: ${CERC_NITRO_CHAIN_URL}
command: ["bash", "./start-server.sh"]
volumes:
- ../config/watcher-mobymask-v3-demo/watcher-config-template.toml:/app/environments/watcher-config-template.toml
- ../config/watcher-mobymask-v3-demo/watcher-config-rates.toml:/app/environments/rates.toml
- ../config/watcher-mobymask-v3-demo/local/keys:/app/keys
- ../config/watcher-mobymask-v3-demo/start-server.sh:/app/start-server.sh
- watcher_nitro_data:/app/out/nitro-db
- nitro_deployment:/nitro
- mobymask_deployment:/server
# Expose GQL, metrics and relay node ports
ports:
- "3001"
- "9001"
- "0.0.0.0:9092:9090"
healthcheck:
test: ["CMD", "busybox", "nc", "localhost", "9090"]
interval: 20s
timeout: 5s
retries: 15
start_period: 5s
extra_hosts:
- "host.docker.internal:host-gateway"
volumes:
mobymask_watcher_db_data:
mobymask_deployment:
nitro_deployment:
watcher_nitro_data:
@@ -5,4 +5,4 @@ services:
environment:
CERC_SCRIPT_DEBUG: ${CERC_SCRIPT_DEBUG}
ports:
- "80"
- "3000"
@@ -0,0 +1,125 @@
#!/bin/bash
# TODO: this file is now an unmodified copy of cerc-io/laconicd/init.sh
# so we should have a mechanism to bundle it inside the container rather than link from here
# at deploy time.
KEY="mykey"
CHAINID="laconic_9000-1"
MONIKER="localtestnet"
KEYRING="test"
KEYALGO="eth_secp256k1"
LOGLEVEL="info"
# trace evm
TRACE="--trace"
# TRACE=""
if [ "$1" == "clean" ] || [ ! -d "$HOME/.laconicd/data/blockstore.db" ]; then
# validate dependencies are installed
command -v jq > /dev/null 2>&1 || { echo >&2 "jq not installed. More info: https://stedolan.github.io/jq/download/"; exit 1; }
# remove existing daemon and client
rm -rf $HOME/.laconicd/*
rm -rf $HOME/.laconic/*
if [ -n "`which make`" ]; then
make install
fi
laconicd config keyring-backend $KEYRING
laconicd config chain-id $CHAINID
# if $KEY exists it should be deleted
laconicd keys add $KEY --keyring-backend $KEYRING --algo $KEYALGO
# Set moniker and chain-id for Ethermint (Moniker can be anything, chain-id must be an integer)
laconicd init $MONIKER --chain-id $CHAINID
# Change parameter token denominations to aphoton
cat $HOME/.laconicd/config/genesis.json | jq '.app_state["staking"]["params"]["bond_denom"]="aphoton"' > $HOME/.laconicd/config/tmp_genesis.json && mv $HOME/.laconicd/config/tmp_genesis.json $HOME/.laconicd/config/genesis.json
cat $HOME/.laconicd/config/genesis.json | jq '.app_state["crisis"]["constant_fee"]["denom"]="aphoton"' > $HOME/.laconicd/config/tmp_genesis.json && mv $HOME/.laconicd/config/tmp_genesis.json $HOME/.laconicd/config/genesis.json
cat $HOME/.laconicd/config/genesis.json | jq '.app_state["gov"]["deposit_params"]["min_deposit"][0]["denom"]="aphoton"' > $HOME/.laconicd/config/tmp_genesis.json && mv $HOME/.laconicd/config/tmp_genesis.json $HOME/.laconicd/config/genesis.json
cat $HOME/.laconicd/config/genesis.json | jq '.app_state["mint"]["params"]["mint_denom"]="aphoton"' > $HOME/.laconicd/config/tmp_genesis.json && mv $HOME/.laconicd/config/tmp_genesis.json $HOME/.laconicd/config/genesis.json
# Custom modules
cat $HOME/.laconicd/config/genesis.json | jq '.app_state["registry"]["params"]["record_rent"]["denom"]="aphoton"' > $HOME/.laconicd/config/tmp_genesis.json && mv $HOME/.laconicd/config/tmp_genesis.json $HOME/.laconicd/config/genesis.json
cat $HOME/.laconicd/config/genesis.json | jq '.app_state["registry"]["params"]["authority_rent"]["denom"]="aphoton"' > $HOME/.laconicd/config/tmp_genesis.json && mv $HOME/.laconicd/config/tmp_genesis.json $HOME/.laconicd/config/genesis.json
cat $HOME/.laconicd/config/genesis.json | jq '.app_state["registry"]["params"]["authority_auction_commit_fee"]["denom"]="aphoton"' > $HOME/.laconicd/config/tmp_genesis.json && mv $HOME/.laconicd/config/tmp_genesis.json $HOME/.laconicd/config/genesis.json
cat $HOME/.laconicd/config/genesis.json | jq '.app_state["registry"]["params"]["authority_auction_reveal_fee"]["denom"]="aphoton"' > $HOME/.laconicd/config/tmp_genesis.json && mv $HOME/.laconicd/config/tmp_genesis.json $HOME/.laconicd/config/genesis.json
cat $HOME/.laconicd/config/genesis.json | jq '.app_state["registry"]["params"]["authority_auction_minimum_bid"]["denom"]="aphoton"' > $HOME/.laconicd/config/tmp_genesis.json && mv $HOME/.laconicd/config/tmp_genesis.json $HOME/.laconicd/config/genesis.json
if [[ "$TEST_REGISTRY_EXPIRY" == "true" ]]; then
echo "Setting timers for expiry tests."
cat $HOME/.laconicd/config/genesis.json | jq '.app_state["registry"]["params"]["record_rent_duration"]="60s"' > $HOME/.laconicd/config/tmp_genesis.json && mv $HOME/.laconicd/config/tmp_genesis.json $HOME/.laconicd/config/genesis.json
cat $HOME/.laconicd/config/genesis.json | jq '.app_state["registry"]["params"]["authority_grace_period"]="60s"' > $HOME/.laconicd/config/tmp_genesis.json && mv $HOME/.laconicd/config/tmp_genesis.json $HOME/.laconicd/config/genesis.json
cat $HOME/.laconicd/config/genesis.json | jq '.app_state["registry"]["params"]["authority_rent_duration"]="60s"' > $HOME/.laconicd/config/tmp_genesis.json && mv $HOME/.laconicd/config/tmp_genesis.json $HOME/.laconicd/config/genesis.json
fi
if [[ "$TEST_AUCTION_ENABLED" == "true" ]]; then
echo "Enabling auction and setting timers."
cat $HOME/.laconicd/config/genesis.json | jq '.app_state["registry"]["params"]["authority_auction_enabled"]=true' > $HOME/.laconicd/config/tmp_genesis.json && mv $HOME/.laconicd/config/tmp_genesis.json $HOME/.laconicd/config/genesis.json
cat $HOME/.laconicd/config/genesis.json | jq '.app_state["registry"]["params"]["authority_rent_duration"]="60s"' > $HOME/.laconicd/config/tmp_genesis.json && mv $HOME/.laconicd/config/tmp_genesis.json $HOME/.laconicd/config/genesis.json
cat $HOME/.laconicd/config/genesis.json | jq '.app_state["registry"]["params"]["authority_grace_period"]="300s"' > $HOME/.laconicd/config/tmp_genesis.json && mv $HOME/.laconicd/config/tmp_genesis.json $HOME/.laconicd/config/genesis.json
cat $HOME/.laconicd/config/genesis.json | jq '.app_state["registry"]["params"]["authority_auction_commits_duration"]="60s"' > $HOME/.laconicd/config/tmp_genesis.json && mv $HOME/.laconicd/config/tmp_genesis.json $HOME/.laconicd/config/genesis.json
cat $HOME/.laconicd/config/genesis.json | jq '.app_state["registry"]["params"]["authority_auction_reveals_duration"]="60s"' > $HOME/.laconicd/config/tmp_genesis.json && mv $HOME/.laconicd/config/tmp_genesis.json $HOME/.laconicd/config/genesis.json
fi
# increase block time (?)
cat $HOME/.laconicd/config/genesis.json | jq '.consensus_params["block"]["time_iota_ms"]="1000"' > $HOME/.laconicd/config/tmp_genesis.json && mv $HOME/.laconicd/config/tmp_genesis.json $HOME/.laconicd/config/genesis.json
# Set gas limit in genesis
cat $HOME/.laconicd/config/genesis.json | jq '.consensus_params["block"]["max_gas"]="10000000"' > $HOME/.laconicd/config/tmp_genesis.json && mv $HOME/.laconicd/config/tmp_genesis.json $HOME/.laconicd/config/genesis.json
# disable produce empty block
if [[ "$OSTYPE" == "darwin"* ]]; then
sed -i '' 's/create_empty_blocks = true/create_empty_blocks = false/g' $HOME/.laconicd/config/config.toml
else
sed -i 's/create_empty_blocks = true/create_empty_blocks = false/g' $HOME/.laconicd/config/config.toml
fi
if [[ $1 == "pending" ]]; then
if [[ "$OSTYPE" == "darwin"* ]]; then
sed -i '' 's/create_empty_blocks_interval = "0s"/create_empty_blocks_interval = "30s"/g' $HOME/.laconicd/config/config.toml
sed -i '' 's/timeout_propose = "3s"/timeout_propose = "30s"/g' $HOME/.laconicd/config/config.toml
sed -i '' 's/timeout_propose_delta = "500ms"/timeout_propose_delta = "5s"/g' $HOME/.laconicd/config/config.toml
sed -i '' 's/timeout_prevote = "1s"/timeout_prevote = "10s"/g' $HOME/.laconicd/config/config.toml
sed -i '' 's/timeout_prevote_delta = "500ms"/timeout_prevote_delta = "5s"/g' $HOME/.laconicd/config/config.toml
sed -i '' 's/timeout_precommit = "1s"/timeout_precommit = "10s"/g' $HOME/.laconicd/config/config.toml
sed -i '' 's/timeout_precommit_delta = "500ms"/timeout_precommit_delta = "5s"/g' $HOME/.laconicd/config/config.toml
sed -i '' 's/timeout_commit = "5s"/timeout_commit = "150s"/g' $HOME/.laconicd/config/config.toml
sed -i '' 's/timeout_broadcast_tx_commit = "10s"/timeout_broadcast_tx_commit = "150s"/g' $HOME/.laconicd/config/config.toml
else
sed -i 's/create_empty_blocks_interval = "0s"/create_empty_blocks_interval = "30s"/g' $HOME/.laconicd/config/config.toml
sed -i 's/timeout_propose = "3s"/timeout_propose = "30s"/g' $HOME/.laconicd/config/config.toml
sed -i 's/timeout_propose_delta = "500ms"/timeout_propose_delta = "5s"/g' $HOME/.laconicd/config/config.toml
sed -i 's/timeout_prevote = "1s"/timeout_prevote = "10s"/g' $HOME/.laconicd/config/config.toml
sed -i 's/timeout_prevote_delta = "500ms"/timeout_prevote_delta = "5s"/g' $HOME/.laconicd/config/config.toml
sed -i 's/timeout_precommit = "1s"/timeout_precommit = "10s"/g' $HOME/.laconicd/config/config.toml
sed -i 's/timeout_precommit_delta = "500ms"/timeout_precommit_delta = "5s"/g' $HOME/.laconicd/config/config.toml
sed -i 's/timeout_commit = "5s"/timeout_commit = "150s"/g' $HOME/.laconicd/config/config.toml
sed -i 's/timeout_broadcast_tx_commit = "10s"/timeout_broadcast_tx_commit = "150s"/g' $HOME/.laconicd/config/config.toml
fi
fi
# Allocate genesis accounts (cosmos formatted addresses)
laconicd add-genesis-account $KEY 100000000000000000000000000aphoton --keyring-backend $KEYRING
# Sign genesis transaction
laconicd gentx $KEY 1000000000000000000000aphoton --keyring-backend $KEYRING --chain-id $CHAINID
# Collect genesis tx
laconicd collect-gentxs
# Run this to ensure everything worked and that the genesis file is setup correctly
laconicd validate-genesis
if [[ $1 == "pending" ]]; then
echo "pending mode is on, please wait for the first block committed."
fi
else
echo "Using existing database at $HOME/.laconicd. To replace, run '`basename $0` clean'"
fi
# Start the node (remove the --pruning=nothing flag if historical queries are not needed)
laconicd start --pruning=nothing --evm.tracer=json $TRACE --log_level $LOGLEVEL --minimum-gas-prices=0.0001aphoton --json-rpc.api eth,txpool,personal,net,debug,web3,miner --api.enable --gql-server --gql-playground
@@ -0,0 +1,2 @@
#!/bin/sh
laconicd keys show mykey | grep address | cut -d ' ' -f 3
@@ -0,0 +1,2 @@
#!/bin/sh
echo y | laconicd keys export mykey --unarmored-hex --unsafe
@@ -0,0 +1,9 @@
services:
cns:
restEndpoint: 'http://laconicd:1317'
gqlEndpoint: 'http://laconicd:9473/api'
userKey: REPLACE_WITH_MYKEY
bondId:
chainId: laconic_9000-1
gas: 350000
fees: 200000aphoton
@@ -65,7 +65,7 @@ if [ -n "$CERC_L1_ADDRESS" ] && [ -n "$CERC_L1_PRIV_KEY" ]; then
# Sequencer
SEQ=$(echo "$wallet3" | awk '/Address:/{print $2}')
SEQ_KEY=$(echo "$wallet3" | awk '/Private key:/{print $3}')
echo "Funding accounts."
wait_for_block 1 300
cast send --from $ADMIN --rpc-url $CERC_L1_RPC --value 5ether $PROPOSER --private-key $ADMIN_KEY
@@ -169,4 +169,4 @@ cp -a /app/packages/contracts-bedrock/deployments/$DEPLOYMENT_CONTEXT /l1-deploy
cp /app/packages/contracts-bedrock/deploy-config/$DEPLOYMENT_CONTEXT.json /l2-config
openssl rand -hex 32 > /l2-config/l2-jwt.txt
echo "Deployment successful. Exiting."
echo "Deployment successful. Exiting"
@@ -1,80 +0,0 @@
#!/bin/bash
set -e
if [ -n "$CERC_SCRIPT_DEBUG" ]; then
set -x
fi
# From env:
# CERC_ETH_RPC_ENDPOINT
# CERC_MOBYMASK_APP_BASE_URI
# CERC_DEPLOYED_CONTRACT
# CERC_PRIVATE_KEY_DEPLOYER
# Check if CERC_DEPLOYED_CONTRACT environment variable set to skip contract deployment
if [ -n "$CERC_DEPLOYED_CONTRACT" ]; then
echo "CERC_DEPLOYED_CONTRACT is set to '$CERC_DEPLOYED_CONTRACT'"
echo "Skipping contract deployment"
exit 0
fi
echo "Using ETH RPC endpoint ${CERC_ETH_RPC_ENDPOINT}"
# Wait till ETH RPC endpoint is available with block number > 1
retry_interval=5
while true; do
block_number_hex=$(curl -s -X POST -H "Content-Type: application/json" --data '{"jsonrpc":"2.0","method":"eth_blockNumber","params":[],"id":1}' ${CERC_ETH_RPC_ENDPOINT} | jq -r '.result')
# Check if the request call was successful
if [ $? -ne 0 ]; then
echo "RPC endpoint not yet available, retrying in $retry_interval seconds..."
sleep $retry_interval
continue
fi
# Convert hex to decimal
block_number_dec=$(printf %u ${block_number_hex})
# Check if block number is > 1 to avoid failures in the deployment
if [ "$block_number_dec" -ge 1 ]; then
echo "RPC endpoint is up"
break
else
echo "RPC endpoint not yet available, retrying in $retry_interval seconds..."
sleep $retry_interval
continue
fi
done
echo "Using CERC_PRIVATE_KEY_DEPLOYER from env"
# Create the required JSON and write it to a file
secrets_file="secrets.json"
secrets_json=$(jq -n \
--arg privateKey "$CERC_PRIVATE_KEY_DEPLOYER" \
--arg rpcUrl "$CERC_ETH_RPC_ENDPOINT" \
--arg baseURI "$CERC_MOBYMASK_APP_BASE_URI" \
'.privateKey = $privateKey | .rpcUrl = $rpcUrl | .baseURI = $baseURI')
echo "$secrets_json" > "${secrets_file}"
export RPC_URL="${CERC_ETH_RPC_ENDPOINT}"
# Check and exit if a deployment already exists (on restarts)
if [ -f ./config.json ]; then
echo "config.json already exists, checking the contract deployment"
# Read JSON file
deployment_details=$(cat config.json)
deployed_contract=$(echo "$deployment_details" | jq -r '.address')
cd ../hardhat
if yarn verifyDeployment --network optimism --contract "${deployed_contract}"; then
echo "Deployment verfication successful"
cd ../server
else
echo "Deployment verfication failed, please clear MobyMask deployment volume before starting"
exit 1
fi
fi
npm run deployAndGenerateInvite
@@ -1,16 +0,0 @@
# Watchers
CERC_ETH_RPC_ENDPOINT="http://op-geth:8545"
# L1 pre-funded account #4, funded on L2 as well
CERC_PRIVATE_KEY_DEPLOYER="0xbe4aa664815ea3bc3d63118649a733f6c96b243744310806ecb6d96359ab62cf"
CERC_MOBYMASK_APP_BASE_URI="http://127.0.0.1:3004/#"
CERC_ETH_RPC_QUERY_ENDPOINT="http://op-geth:8545"
CERC_ETH_RPC_MUTATION_ENDPOINT="http://op-geth:8545"
CERC_NITRO_CHAIN_URL="http://op-geth:8546"
# App
CERC_APP_WATCHER_URL="http://localhost:3001"
CERC_SNAP_URL=http://localhost:8080
@@ -1,72 +0,0 @@
#!/bin/bash
set -e
if [ -n "$CERC_SCRIPT_DEBUG" ]; then
set -x
fi
echo "*************************************"
CERC_L1_RPC="${CERC_L1_RPC:-${DEFAULT_CERC_L1_RPC}}"
CERC_L1_CHAIN_ID="${CERC_L1_CHAIN_ID:-${DEFAULT_CERC_L1_CHAIN_ID}}"
CERC_L1_ACCOUNTS_CSV_URL="${CERC_L1_ACCOUNTS_CSV_URL:-${DEFAULT_CERC_L1_ACCOUNTS_CSV_URL}}"
# Fixture accounts
WATCHER_1_ACCOUNT=0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266
WATCHER_2_ACCOUNT=0x70997970C51812dc3A010C7d01b50e0d17dc79C8
WATCHER_3_ACCOUNT=0x15d34AAf54267DB7D7c367839AAf71A00a2C6A65
NITRO_APP_ACCOUNT=0xbDA5747bFD65F08deb54cb465eB87D40e51B197E
WATCHER_1_ACCOUNT_KEY=0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80
WATCHER_2_ACCOUNT_KEY=0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d
WATCHER_3_ACCOUNT_KEY=0x47e179ec197488593b187f80a00eb0da91f1b9d0b13f8733639f19c30a34926a
NITRO_APP_ACCOUNT_KEY=0x689af8efa8c651a91ad287602527f3af2fe9f6501a7ac4b061667b5a93e037fd
# Check if watcher 1 account already funded
WATCHER_1_ACCOUNT_BALANCE=$(cast balance ${WATCHER_1_ACCOUNT} --rpc-url $CERC_L1_RPC)
echo "WATCHER_1_ACCOUNT_BALANCE ${WATCHER_1_ACCOUNT_BALANCE}"
if [ "$WATCHER_1_ACCOUNT_BALANCE" != "0" ]; then
echo "Watcher account already funded, exiting."
exit 0
fi
echo "Funding accounts on L2"
# Fetch the L1 funded accounts
curl -o accounts.csv $CERC_L1_ACCOUNTS_CSV_URL
# Use the accounts other than the ones used for Optimism deployment
ACCOUNT_1=$(awk -F ',' 'NR == 5 {print $2}' accounts.csv)
ACCOUNT_1_KEY=$(awk -F ',' 'NR == 5 {print $3}' accounts.csv)
ACCOUNT_2=$(awk -F ',' 'NR == 6 {print $2}' accounts.csv)
ACCOUNT_2_KEY=$(awk -F ',' 'NR == 6 {print $3}' accounts.csv)
# Get the bridge contract address
DEPLOYMENT_CONTEXT="$CERC_L1_CHAIN_ID"
BRIDGE=$(cat /l1-deployment/$DEPLOYMENT_CONTEXT/L1StandardBridgeProxy.json | jq -r .address)
# Send balance to bridge contract on L1
cast send --rpc-url $CERC_L1_RPC --from $ACCOUNT_1 --value 10000ether $BRIDGE --private-key $ACCOUNT_1_KEY
cast send --rpc-url $CERC_L1_RPC --from $ACCOUNT_2 --value 10000ether $BRIDGE --private-key $ACCOUNT_2_KEY
echo "Following accounts have been funded; use them for transactions on L2:"
echo "${ACCOUNT_1}"
echo "${ACCOUNT_2}"
echo "*************************************"
echo "Funding the watcher and app Nitro accounts on L2"
cast send --rpc-url $CERC_L1_RPC --from $ACCOUNT_1 --value 200ether $WATCHER_1_ACCOUNT --private-key $ACCOUNT_1_KEY
cast send --rpc-url $CERC_L1_RPC --from $ACCOUNT_1 --value 200ether $WATCHER_2_ACCOUNT --private-key $ACCOUNT_1_KEY
cast send --rpc-url $CERC_L1_RPC --from $ACCOUNT_1 --value 200ether $WATCHER_3_ACCOUNT --private-key $ACCOUNT_1_KEY
cast send --rpc-url $CERC_L1_RPC --from $ACCOUNT_1 --value 200ether $NITRO_APP_ACCOUNT --private-key $ACCOUNT_1_KEY
cast send --rpc-url $CERC_L1_RPC --from $WATCHER_1_ACCOUNT --value 100ether $BRIDGE --private-key $WATCHER_1_ACCOUNT_KEY
sleep 5
cast send --rpc-url $CERC_L1_RPC --from $WATCHER_2_ACCOUNT --value 100ether $BRIDGE --private-key $WATCHER_2_ACCOUNT_KEY
sleep 5
cast send --rpc-url $CERC_L1_RPC --from $WATCHER_3_ACCOUNT --value 100ether $BRIDGE --private-key $WATCHER_3_ACCOUNT_KEY
sleep 5
cast send --rpc-url $CERC_L1_RPC --from $NITRO_APP_ACCOUNT --value 100ether $BRIDGE --private-key $NITRO_APP_ACCOUNT_KEY
echo "Done, exiting."
@@ -1,21 +0,0 @@
{
"peerId": {
"id": "12D3KooWAMjBkFCT9DtCnSDcxftxJzSuTBvzVojabv64cnEvX4AZ",
"privKey": "CAESQAKCrnY0QKTky1I18fqn+VPydXGUv1NYiV+nVKqBFkw/CAjE9sKKIDGnYAo8mivnI6dngFenERY+0Q8AJrPTaXY=",
"pubKey": "CAESIAgIxPbCiiAxp2AKPJor5yOnZ4BXpxEWPtEPACaz02l2"
},
"relayPeerId": {
"id": "12D3KooWNQJDGtH3YAZk2qG1ZbcoQvw6HaD814pfd9HHQthgX63K",
"privKey": "CAESQGc996T2OuyV3aY+hnna+GIexKBEcE6jDNX/RaofHr58uv2EYxXm4kcL2tO2tKgnPgtkegHFdjqy6h/xOA+YMZo=",
"pubKey": "CAESILr9hGMV5uJHC9rTtrSoJz4LZHoBxXY6suof8TgPmDGa"
},
"peer": {
"privateKey": "ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80",
"nitroAddress": "0xAAA6628Ec44A8a742987EF3A114dDFE2D4F7aDCE",
"nitroPrivateKey": "2d999770f7b5d49b694080f987b82bbc9fc9ac2b4dcc10b0f8aba7d700f69c6d"
},
"consensus": {
"publicKey": "02cd17b05ca998955be5ca7bf4fd4531243d438f1aae7ce8a0ed5159f53cee5b40",
"privateKey": "67d80505614bdf61fca11cbad31d93acb2c7df1c653dc25975d77d05f05f154f"
}
}
@@ -1,21 +0,0 @@
{
"peerId": {
"id": "12D3KooWBNEbY3QS4y23ngupDw9PDc4bvNvRJGVRejjV9EZLjux5",
"privKey": "CAESQGSTw0ymvn8+wX9Dbvyr4/Gib1q2voe0CC0VyeClMQP6FwW14x0fpRbBIx0XhLdxWHkRndphVg3gVAHyC+7ZI8o=",
"pubKey": "CAESIBcFteMdH6UWwSMdF4S3cVh5EZ3aYVYN4FQB8gvu2SPK"
},
"relayPeerId": {
"id": "12D3KooWPpBt2coC5BKEsewogHSkdgdyY9guUHJBgJFZoh66R4UL",
"privKey": "CAESQBdoGZzpiHsE8GlIhGGP+tl6A13sIPxOhgSwsWZR4cwmz/f7627X5GQRLD41ikH6oZ7ZeSbiiPsBtelL1+t3M80=",
"pubKey": "CAESIM/3++tu1+RkESw+NYpB+qGe2Xkm4oj7AbXpS9frdzPN"
},
"peer": {
"privateKey": "59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d",
"nitroAddress": "0xBBB676f9cFF8D242e9eaC39D063848807d3D1D94",
"nitroPrivateKey": "0279651921cd800ac560c21ceea27aab0107b67daf436cdd25ce84cad30159b4"
},
"consensus": {
"publicKey": "029c8035b3e9401b8f178f7c37285b5cb22501e017340e2058b3b842f2a1f0ae45",
"privateKey": "0261008e8e3ec808168e99333599da38ca59a056a2ae4510a6ad3d8b5cb0918c"
}
}
@@ -1,21 +0,0 @@
{
"peerId": {
"id": "12D3KooWSRH6ftgkAZsKZK7UX1Zr6Hx6YAsEepHqzopFszqfTxxi",
"privKey": "CAESQHBjlHxfVhZ2gXsBItrIEEgSGKcjMkFiGs3PPz9E3ace9qyWEkvR4oit5ve9SAROVoh20hoa42IC91NIafMaqws=",
"pubKey": "CAESIPaslhJL0eKIreb3vUgETlaIdtIaGuNiAvdTSGnzGqsL"
},
"relayPeerId": {
"id": "12D3KooWLudDC3NnS8k9xLiqTZcS9xbFNrGSttu5GPynQgNgenPW",
"privKey": "CAESQHuEXPB1hTQATlZaNRQnAfSvnfYUeLF9PjSNKp9L33K2pMl37tTBYghnfQ0yluse0zHOIXRJM+9+ARn9+jIr0gU=",
"pubKey": "CAESIKTJd+7UwWIIZ30NMpbrHtMxziF0STPvfgEZ/foyK9IF"
},
"peer": {
"privateKey": "47e179ec197488593b187f80a00eb0da91f1b9d0b13f8733639f19c30a34926a",
"nitroAddress": "0x67D5b55604d1aF90074FcB69b8C51838FFF84f8d",
"nitroPrivateKey": "58368d20ff12f17669c06158c21d885897aa56f9be430edc789614bf9851d53f"
},
"consensus": {
"publicKey": "039160c244a7ad8be16a64bdb69e6dbacdcfe20b37076792a0d06032a8097468ca",
"privateKey": "8894685fe81001d75662b079905472699373967451d1255ee5fc669d0a09a9ca"
}
}
@@ -1,68 +0,0 @@
#!/bin/bash
set -e
if [ -n "$CERC_SCRIPT_DEBUG" ]; then
set -x
fi
watcher_keys_dir="/server/keys"
# Configure relay nodes to connect to
# Note: Assuming host ports for watchers (1-3) relay nodes
RELAY_NODES="[\"/ip4/127.0.0.1/tcp/9090/ws/p2p/$(jq -r '.relayPeerId.id' ${watcher_keys_dir}/watcher-1.json)\", \"/ip4/127.0.0.1/tcp/9091/ws/p2p/$(jq -r '.relayPeerId.id' ${watcher_keys_dir}/watcher-2.json)\", \"/ip4/127.0.0.1/tcp/9092/ws/p2p/$(jq -r '.relayPeerId.id' ${watcher_keys_dir}/watcher-3.json)\"]"
# Configure watcher (1) Nitro account to make payments to
PAYMENT_NITRO_ADDRESS=$(jq -r '.peer.nitroAddress' ${watcher_keys_dir}/watcher-1.json)
echo "Using RELAY_NODES $RELAY_NODES"
echo "Using PAYMENT_NITRO_ADDRESS $PAYMENT_NITRO_ADDRESS"
# Use config from mounted volume
echo "Taking config for deployed contracts from mounted volume"
while [ ! -f /server/config.json ]; do
echo "Config not found, retrying in 5 seconds..."
sleep 5
done
# Get deployed contract address and chain id
DEPLOYED_CONTRACT=$(jq -r '.address' /server/config.json | tr -d '"')
CHAIN_ID=$(jq -r '.chainId' /server/config.json)
echo "Using DEPLOYED_CONTRACT $DEPLOYED_CONTRACT"
echo "Using CHAIN_ID $CHAIN_ID"
nitro_addresses_file="/nitro/nitro-addresses.json"
nitro_addresses_destination_file="/app/src/utils/nitro-addresses.json"
if [ -f ${nitro_addresses_file} ]; then
echo "Using Nitro addresses from ${nitro_addresses_file}:"
cat "$nitro_addresses_file"
cat "$nitro_addresses_file" > "$nitro_addresses_destination_file"
else
echo "Nitro addresses not available"
exit 1
fi
# Export config values in a json file
app_config_file="/app/src/utils/config.json"
app_config_json=$(jq -n \
--arg name "MobyMask" \
--argjson enableDebugInfo true \
--arg address "$DEPLOYED_CONTRACT" \
--argjson chainId "$CHAIN_ID" \
--argjson relayNodes "$RELAY_NODES" \
--argjson denyMultiaddrs "[]" \
--arg pubsub "" \
--argjson directPeers "[]" \
'.name = $name | .address = $address | .chainId = $chainId | .relayNodes = $relayNodes | .peer.enableDebugInfo = $enableDebugInfo | .peer.denyMultiaddrs = $denyMultiaddrs | .peer.pubsub = $pubsub | .peer.directPeers = $directPeers')
echo "$app_config_json" > "${app_config_file}"
echo "Using CERC_APP_WATCHER_URL $CERC_APP_WATCHER_URL"
echo "Using CERC_SNAP_URL $CERC_SNAP_URL"
REACT_APP_DEBUG_PEER=true \
REACT_APP_WATCHER_URI="$CERC_APP_WATCHER_URL/graphql" \
REACT_APP_PAY_TO_NITRO_ADDRESS="$PAYMENT_NITRO_ADDRESS" \
REACT_APP_SNAP_ORIGIN="local:$CERC_SNAP_URL" \
yarn build
http-server -p 80 /app/build
@@ -1,119 +0,0 @@
#!/bin/bash
set -e
if [ -n "$CERC_SCRIPT_DEBUG" ]; then
set -x
fi
watcher_keys_dir="./keys"
echo "Watcher index: ${CERC_WATCHER_INDEX}"
echo "Using RPC query endpoint ${CERC_ETH_RPC_QUERY_ENDPOINT}"
echo "Using RPC mutation endpoint ${CERC_ETH_RPC_MUTATION_ENDPOINT}"
echo "Using Nitro chain URL ${CERC_NITRO_CHAIN_URL}"
WATCHER_DB="mobymask-watcher-${CERC_WATCHER_INDEX}"
# Use the docker container's host IP for relay multiaddr in peer config
CERC_RELAY_MULTIADDR="/dns4/mobymask-watcher-${CERC_WATCHER_INDEX}-server/tcp/9090/ws/p2p/$(jq -r '.relayPeerId.id' ${watcher_keys_dir}/watcher-${CERC_WATCHER_INDEX}.json)"
# Assign deployed contract address from server config (created by mobymask container after deploying contract)
CONTRACT_ADDRESS=$(jq -r '.address' /server/config.json | tr -d '"')
nitro_addresses_file="/nitro/nitro-addresses.json"
nitro_addresses_destination_file="./src/nitro-addresses.json"
if [ -f ${nitro_addresses_file} ]; then
echo "Using Nitro addresses from ${nitro_addresses_file}:"
cat "$nitro_addresses_file"
cat "$nitro_addresses_file" > "$nitro_addresses_destination_file"
else
echo "Nitro addresses not available"
exit 1
fi
# Build after setting the Nitro addresses
yarn build
PEER_ID_FILE='./peer-id.json'
RELAY_PEER_ID_FILE='./relay-id.json'
# Create watcher party array
watcher_parties=()
# Iterate over each fixture JSON file
for watcher_keys_file in "$watcher_keys_dir"/*.json; do
# Extract the filename without the path and extension
filename=$(basename "$watcher_keys_file" .json)
# Read the consensus keys
peer_id=$(jq -r '.peerId.id' "$watcher_keys_file")
# Read the consensus keys
consensus_public_key=$(jq -r '.consensus.publicKey' "$watcher_keys_file")
consensus_private_key=$(jq -r '.consensus.privateKey' "$watcher_keys_file")
# Append watcher party
watcher_party=$(jq -n \
--arg peerId "$peer_id" \
--arg publicKey "$consensus_public_key" \
'.peerId = $peerId | .publicKey = $publicKey')
watcher_parties+=("$watcher_party")
if [ "$filename" = "watcher-${CERC_WATCHER_INDEX}" ]; then
# Export watcher peer and relay ids
peer_id_data=$(jq '.peerId' "$watcher_keys_file")
relay_peer_id_data=$(jq '.relayPeerId' "$watcher_keys_file")
echo "$peer_id_data" > "${PEER_ID_FILE}"
echo "$relay_peer_id_data" > "${RELAY_PEER_ID_FILE}"
# Set peer and nitro account keys
CERC_PRIVATE_KEY_PEER=$(jq -r '.peer.privateKey' "$watcher_keys_file")
CERC_WATCHER_NITRO_PK=$(jq -r '.peer.nitroPrivateKey' "$watcher_keys_file")
# Set consensus keys for this peer
CONSENSUS_PUBLIC_KEY=${consensus_public_key}
CONSENSUS_PRIVATE_KEY=${consensus_private_key}
fi
done
echo "Consensus module enabled"
CONSENSUS_ENABLED=true
WATCHER_PARTY_PEERS_FILE='./watcher-party-peers.json'
# Export watcher party file
watcher_parties_json=$(printf '%s\n' "${watcher_parties[@]}" | jq -s .)
echo "$watcher_parties_json" > "${WATCHER_PARTY_PEERS_FILE}"
echo "Watcher party peers exported to ${WATCHER_PARTY_PEERS_FILE}"
# Configure relay peers for watcher 2 and 3
CERC_RELAY_PEERS=[]
if [ "${CERC_WATCHER_INDEX}" = "2" ]; then
# 2 -> 1
CERC_RELAY_PEERS="['/dns4/mobymask-watcher-1-server/tcp/9090/ws/p2p/$(jq -r '.relayPeerId.id' ${watcher_keys_dir}/watcher-1.json)']"
elif [ "${CERC_WATCHER_INDEX}" = "3" ]; then
# 3 -> 1, 2
CERC_RELAY_PEERS="['/dns4/mobymask-watcher-1-server/tcp/9090/ws/p2p/$(jq -r '.relayPeerId.id' ${watcher_keys_dir}/watcher-1.json)', '/dns4/mobymask-watcher-2-server/tcp/9090/ws/p2p/$(jq -r '.relayPeerId.id' ${watcher_keys_dir}/watcher-2.json)']"
fi
# Read in the config template TOML file and modify it
WATCHER_CONFIG_TEMPLATE=$(cat environments/watcher-config-template.toml)
WATCHER_CONFIG=$(echo "$WATCHER_CONFIG_TEMPLATE" | \
sed -E "s|REPLACE_WITH_CERC_RELAY_PEERS|${CERC_RELAY_PEERS}|g; \
s|REPLACE_WITH_CERC_RELAY_MULTIADDR|${CERC_RELAY_MULTIADDR}|g; \
s/REPLACE_WITH_CERC_PRIVATE_KEY_PEER/${CERC_PRIVATE_KEY_PEER}/g; \
s/REPLACE_WITH_CERC_WATCHER_NITRO_PK/${CERC_WATCHER_NITRO_PK}/g; \
s/REPLACE_WITH_CONTRACT_ADDRESS/${CONTRACT_ADDRESS}/g; \
s|REPLACE_WITH_CERC_NITRO_CHAIN_URL|${CERC_NITRO_CHAIN_URL}|g; \
s/REPLACE_WITH_CONSENSUS_ENABLED/${CONSENSUS_ENABLED}/g; \
s/REPLACE_WITH_CONSENSUS_PUBLIC_KEY/${CONSENSUS_PUBLIC_KEY}/g; \
s/REPLACE_WITH_CONSENSUS_PRIVATE_KEY/${CONSENSUS_PRIVATE_KEY}/g; \
s|REPLACE_WITH_WATCHER_PARTY_PEERS_FILE|${WATCHER_PARTY_PEERS_FILE}|g; \
s|REPLACE_WITH_CERC_ETH_RPC_QUERY_ENDPOINT|${CERC_ETH_RPC_QUERY_ENDPOINT}|g; \
s|REPLACE_WITH_CERC_ETH_RPC_MUTATION_ENDPOINT|${CERC_ETH_RPC_MUTATION_ENDPOINT}|g; \
s|REPLACE_WITH_WATCHER_DB|${WATCHER_DB}| ")
# Write the modified content to a new file
echo "$WATCHER_CONFIG" > environments/local.toml
echo 'Running watcher server'
yarn server
@@ -1,14 +0,0 @@
freeQueriesLimit = 10
freeQueriesList = []
[queries]
multiNonce = '50'
_owner = '50'
isRevoked = '50'
isPhisher = '50'
isMember = '50'
[mutations]
invoke = '100'
revoke = '100'
@@ -1,111 +0,0 @@
[server]
host = "0.0.0.0"
port = 3001
kind = "lazy"
# Checkpointing state.
checkpointing = false
# Checkpoint interval in number of blocks.
checkpointInterval = 2000
# Enable state creation
enableState = false
# Boolean to filter logs by contract.
filterLogs = true
# Max block range for which to return events in eventsInRange GQL query.
# Use -1 for skipping check on block range.
maxEventsBlockRange = -1
# Flag to specify whether RPC endpoint supports block hash as block tag parameter
rpcSupportsBlockHashParam = true
[server.p2p]
enableRelay = true
enablePeer = true
[server.p2p.relay]
host = "0.0.0.0"
port = 9090
relayPeers = REPLACE_WITH_CERC_RELAY_PEERS
denyMultiaddrs = []
peerIdFile = './relay-id.json'
announce = ''
pubsub = ''
enableDebugInfo = true
[server.p2p.peer]
relayMultiaddr = 'REPLACE_WITH_CERC_RELAY_MULTIADDR'
pubSubTopic = 'mobymask'
denyMultiaddrs = []
peerIdFile = './peer-id.json'
pubsub = ''
enableDebugInfo = true
enableL2Txs = true
pingInterval = 4000
pingTimeout = 1500
maxRelayConnections = 10
[server.p2p.peer.l2TxsConfig]
privateKey = 'REPLACE_WITH_CERC_PRIVATE_KEY_PEER'
contractAddress = 'REPLACE_WITH_CONTRACT_ADDRESS'
[server.p2p.nitro]
chainUrl = 'REPLACE_WITH_CERC_NITRO_CHAIN_URL'
store = './out/nitro-db'
privateKey = 'REPLACE_WITH_CERC_WATCHER_NITRO_PK'
chainPrivateKey = 'REPLACE_WITH_CERC_PRIVATE_KEY_PEER'
[server.p2p.nitro.payments]
ratesFile = './environments/rates.toml'
requestTimeoutInSecs = 10
[server.p2p.nitro.payments.cache]
maxAccounts = 1000
accountTTLInSecs = 1800
maxVouchersPerAccount = 1000
voucherTTLInSecs = 300
maxPaymentChannels = 10000
paymentChannelTTLInSecs = 1800
[server.p2p.consensus]
enabled = REPLACE_WITH_CONSENSUS_ENABLED
publicKey = 'REPLACE_WITH_CONSENSUS_PUBLIC_KEY'
privateKey = 'REPLACE_WITH_CONSENSUS_PRIVATE_KEY'
watcherPartyPeersFile = 'REPLACE_WITH_WATCHER_PARTY_PEERS_FILE'
[metrics]
host = "0.0.0.0"
port = 9000
[metrics.gql]
port = 9001
[database]
type = "postgres"
host = "mobymask-watcher-db"
port = 5432
database = "REPLACE_WITH_WATCHER_DB"
username = "vdbm"
password = "password"
synchronize = true
logging = false
[upstream]
[upstream.ethServer]
gqlApiEndpoint = "http://ipld-eth-server:8083/graphql"
rpcProviderEndpoint = 'REPLACE_WITH_CERC_ETH_RPC_QUERY_ENDPOINT'
rpcProviderMutationEndpoint = 'REPLACE_WITH_CERC_ETH_RPC_MUTATION_ENDPOINT'
[upstream.cache]
name = "requests"
enabled = false
deleteOnStart = false
[jobQueue]
dbConnectionString = "postgres://vdbm:password@mobymask-watcher-db/REPLACE_WITH_WATCHER_DB-job-queue"
maxCompletionLagInSecs = 300
jobDelayInMilliSecs = 100
eventsInBatch = 50
blockDelayInMilliSecs = 60000
@@ -1,2 +1,2 @@
#!/bin/sh
sed 's/REPLACE_WITH_MYKEY/'${1}'/' registry-cli-config-template.yml > config.yml
sed 's/REPLACE_WITH_MYKEY/'${1}'/' /registry-cli-config/registry-cli-config-template.yml > config.yml
@@ -1,4 +0,0 @@
#!/usr/bin/env bash
# Build the mars-v2 image
source ${CERC_CONTAINER_BASE_DIR}/build-base.sh
docker build -t cerc/mars-v2:local -f ${CERC_REPO_BASE_DIR}/mars-v2-frontend/Dockerfile ${build_command_args} ${CERC_REPO_BASE_DIR}/mars-v2-frontend
@@ -1,4 +0,0 @@
#!/usr/bin/env bash
# Build the mars image
source ${CERC_CONTAINER_BASE_DIR}/build-base.sh
docker build -t cerc/mars:local -f ${CERC_REPO_BASE_DIR}/mars-interface/Dockerfile ${build_command_args} ${CERC_REPO_BASE_DIR}/mars-interface
@@ -33,8 +33,8 @@ if [ -f ".env" ]; then
rm -f $TMP_ENV
fi
for f in $(find . -type f \( -regex '.*.html?' -or -regex ".*.[tj]s\(x\|on\)?$" \) | grep -v 'node_modules' | grep -v '.git'); do
for e in $(cat "${f}" | tr -s '[:blank:]' '\n' | tr -s '["/\\{},();]' '\n' | tr -s "[']" '\n' | egrep -o -e '^CERC_RUNTIME_ENV_.+$' -e '^LACONIC_HOSTED_CONFIG_.+$'); do
for f in $(find "$TRG_DIR" -regex ".*.[tj]sx?$" -type f | grep -v 'node_modules'); do
for e in $(cat "${f}" | tr -s '[:blank:]' '\n' | tr -s '[{},();]' '\n' | egrep -o '^"CERC_RUNTIME_ENV_[^\"]+"'); do
orig_name=$(echo -n "${e}" | sed 's/"//g')
cur_name=$(echo -n "${orig_name}" | sed 's/CERC_RUNTIME_ENV_//g')
cur_val=$(echo -n "\$${cur_name}" | envsubst)
@@ -3,17 +3,12 @@ FROM cerc/foundry:local
# Install node (local foundry is a debian based image)
RUN apt-get update \
&& apt-get install -y curl wget \
&& apt-get install -y git busybox jq python3 make gcc g++
RUN curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash \
&& export NVM_DIR="$HOME/.nvm" \
&& [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" \
&& nvm install 16.16.0 \
&& curl --silent --location https://deb.nodesource.com/setup_16.x | bash - \
&& apt-get update \
&& apt-get install -y nodejs git busybox jq \
&& node -v
SHELL ["/bin/bash", "-c"]
RUN source $HOME/.bashrc \
&& corepack enable \
RUN corepack enable \
&& yarn --version
WORKDIR /app
@@ -21,10 +16,7 @@ WORKDIR /app
# Copy optimism repo contents
COPY . .
SHELL ["/bin/bash", "-c"]
RUN source $HOME/.bashrc \
&& echo "Building optimism" \
&& pnpm i -g pnpm@8.15.3 \
&& pnpm install && pnpm build
RUN echo "Building optimism" && \
pnpm install && pnpm build
WORKDIR /app/packages/contracts-bedrock
@@ -1,5 +0,0 @@
#!/usr/bin/env bash
# Build the ping pub image
source ${CERC_CONTAINER_BASE_DIR}/build-base.sh
docker build -t cerc/ping-pub:local ${build_command_args} -f $CERC_REPO_BASE_DIR/explorer/Dockerfile $CERC_REPO_BASE_DIR/explorer
@@ -1,6 +0,0 @@
FROM cerc/snowballtools-base-backend-base:local
WORKDIR /app/packages/backend
COPY run.sh .
ENTRYPOINT ["./run.sh"]
@@ -1,26 +0,0 @@
FROM ubuntu:22.04 as builder
RUN apt update && \
apt install -y --no-install-recommends --no-install-suggests \
ca-certificates curl gnupg
# Node
ARG NODE_MAJOR=20
RUN curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg && \
echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_$NODE_MAJOR.x nodistro main" | tee /etc/apt/sources.list.d/nodesource.list && \
apt update && apt install -y nodejs
# npm setup
RUN npm config set @cerc-io:registry https://git.vdb.to/api/packages/cerc-io/npm/ && npm install -g yarn
COPY . /app/
WORKDIR /app/
RUN find . -name 'node_modules' | xargs -n1 rm -rf
RUN yarn && yarn build --ignore frontend
FROM cerc/webapp-base:local
COPY --from=builder /app /app
WORKDIR /app/packages/backend
@@ -1,10 +0,0 @@
#!/usr/bin/env bash
# Build cerc/webapp-deployer-backend
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/snowballtools-base-backend-base:local ${build_command_args} -f ${SCRIPT_DIR}/Dockerfile-base ${CERC_REPO_BASE_DIR}/snowballtools-base
docker build -t cerc/snowballtools-base-backend:local ${build_command_args} ${SCRIPT_DIR}
@@ -1,19 +0,0 @@
#!/bin/bash
LACONIC_HOSTED_CONFIG_FILE=${LACONIC_HOSTED_CONFIG_FILE}
if [ -z "${LACONIC_HOSTED_CONFIG_FILE}" ]; then
if [ -f "/config/laconic-hosted-config.yml" ]; then
LACONIC_HOSTED_CONFIG_FILE="/config/laconic-hosted-config.yml"
elif [ -f "/config/config.yml" ]; then
LACONIC_HOSTED_CONFIG_FILE="/config/config.yml"
fi
fi
if [ -f "${LACONIC_HOSTED_CONFIG_FILE}" ]; then
/scripts/apply-webapp-config.sh $LACONIC_HOSTED_CONFIG_FILE "`pwd`/dist"
fi
/scripts/apply-runtime-env.sh "`pwd`/dist"
yarn start
@@ -1,44 +1,22 @@
#!/usr/bin/env bash
set -e
if [ -n "$CERC_SCRIPT_DEBUG" ]; then
set -x
fi
echo "Test container starting"
DATA_DEVICE=$(df | grep "/data$" | awk '{ print $1 }')
if [[ -n "$DATA_DEVICE" ]]; then
echo "/data: MOUNTED dev=${DATA_DEVICE}"
else
echo "/data: not mounted"
fi
DATA2_DEVICE=$(df | grep "/data2$" | awk '{ print $1 }')
if [[ -n "$DATA_DEVICE" ]]; then
echo "/data2: MOUNTED dev=${DATA2_DEVICE}"
else
echo "/data2: not mounted"
fi
# Test if the container's filesystem is old (run previously) or new
for d in /data /data2; do
if [[ -f "$d/exists" ]];
then
TIMESTAMP=`cat $d/exists`
echo "$d filesystem is old, created: $TIMESTAMP"
else
echo "$d filesystem is fresh"
echo `date` > $d/exists
fi
done
EXISTSFILENAME=/data/exists
echo "Test container starting"
if [[ -f "$EXISTSFILENAME" ]];
then
TIMESTAMP=`cat $EXISTSFILENAME`
echo "Filesystem is old, created: $TIMESTAMP"
else
echo "Filesystem is fresh"
echo `date` > $EXISTSFILENAME
fi
if [ -n "$CERC_TEST_PARAM_1" ]; then
echo "Test-param-1: ${CERC_TEST_PARAM_1}"
fi
if [ -n "$CERC_TEST_PARAM_2" ]; then
echo "Test-param-2: ${CERC_TEST_PARAM_2}"
fi
if [ -d "/config" ]; then
echo "/config: EXISTS"
@@ -1,12 +0,0 @@
FROM ubuntu:latest
RUN apt-get update && export DEBIAN_FRONTEND=noninteractive && export DEBCONF_NOWARNINGS="yes" && \
apt-get install -y software-properties-common && \
apt-get install -y postgresql-client && \
apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
EXPOSE 80
COPY run.sh /app/run.sh
ENTRYPOINT ["/app/run.sh"]
@@ -1,5 +0,0 @@
#!/usr/bin/env bash
# Build cerc/test-container
source ${CERC_CONTAINER_BASE_DIR}/build-base.sh
SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
docker build -t cerc/test-database-client:local -f ${SCRIPT_DIR}/Dockerfile ${build_command_args} $SCRIPT_DIR
@@ -1,71 +0,0 @@
#!/usr/bin/env bash
set -e
if [ -n "$CERC_SCRIPT_DEBUG" ]; then
set -x
fi
# TODO derive this from config
database_url="postgresql://test-user:password@localhost:5432/test-db"
psql_command="psql ${database_url}"
program_name="Database test client:"
wait_for_database_up () {
for i in {1..50}
do
${psql_command} -c "select 1;"
psql_succeeded=$?
if [[ ${psql_succeeded} == 0 ]]; then
# if ready, return
echo "${program_name} database up"
return
else
# if not ready, wait
echo "${program_name} waiting for database: ${i}"
sleep 5
fi
done
# Timed out, error exit
echo "${program_name} waiting for database: FAILED"
exit 1
}
# Used to synchronize with the test runner
notify_test_complete () {
echo "${program_name} test complete"
}
does_test_data_exist () {
query_result=$(${psql_command} -t -c "select count(*) from test_table_1 where key_column = 'test_key_1';" | head -1 | tr -d ' ')
if [[ "${query_result}" == "1" ]]; then
return 0
else
return 1
fi
}
create_test_data () {
${psql_command} -c "create table test_table_1 (key_column text, value_column text, primary key(key_column));"
${psql_command} -c "insert into test_table_1 values ('test_key_1', 'test_value_1');"
}
wait_forever() {
# Loop to keep docker/k8s happy since this is the container entrypoint
while :; do sleep 600; done
}
wait_for_database_up
# Check if the test database content exists already
if does_test_data_exist; then
# If so, log saying so. Test harness will look for this log output
echo "${program_name} test data already exists"
else
# Otherwise log saying the content was not present
echo "${program_name} test data does not exist"
echo "${program_name} creating test data"
# then create it
create_test_data
fi
notify_test_complete
wait_forever
@@ -1,3 +0,0 @@
FROM postgres:16-bullseye
EXPOSE 5432
@@ -1,5 +0,0 @@
#!/usr/bin/env bash
# Build cerc/test-container
source ${CERC_CONTAINER_BASE_DIR}/build-base.sh
SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
docker build -t cerc/test-database-container:local -f ${SCRIPT_DIR}/Dockerfile ${build_command_args} $SCRIPT_DIR
@@ -43,6 +43,7 @@ COPY scripts /scripts
# RUN su node -c "npm install -g <your-package-list-here>"
RUN mkdir -p /config
COPY ./config.yml /config
# Install simple web server for now (use nginx perhaps later)
RUN yarn global add http-server
@@ -0,0 +1 @@
# Put config here.
@@ -18,8 +18,8 @@ if [ -f ".env" ]; then
rm -f $TMP_ENV
fi
for f in $(find . -type f \( -regex '.*.html?' -or -regex ".*.[tj]s\(x\|on\)?$" \) | grep -v 'node_modules' | grep -v '.git'); do
for e in $(cat "${f}" | tr -s '[:blank:]' '\n' | tr -s '["/\\{},();]' '\n' | tr -s "[']" '\n' | egrep -o -e '^CERC_RUNTIME_ENV_.+$' -e '^LACONIC_HOSTED_CONFIG_.+$'); do
for f in $(find . -regex ".*.[tj]sx?$" -type f | grep -v 'node_modules'); do
for e in $(cat "${f}" | tr -s '[:blank:]' '\n' | tr -s '[{},();]' '\n' | egrep -o -e '^"CERC_RUNTIME_ENV_[^\"]+"' -e '^"LACONIC_HOSTED_CONFIG_[^\"]+"'); do
orig_name=$(echo -n "${e}" | sed 's/"//g')
cur_name=$(echo -n "${orig_name}" | sed 's/CERC_RUNTIME_ENV_//g')
cur_val=$(echo -n "\$${cur_name}" | envsubst)
@@ -11,13 +11,7 @@ WORK_DIR="${1:-/app}"
OUTPUT_DIR="${2:-build}"
DEST_DIR="${3:-/data}"
if [ -f "${WORK_DIR}/build-webapp.sh" ]; then
echo "Building webapp with ${WORK_DIR}/build-webapp.sh ..."
cd "${WORK_DIR}" || exit 1
rm -rf "${DEST_DIR}"
./build-webapp.sh "${DEST_DIR}" || exit 1
elif [ -f "${WORK_DIR}/package.json" ]; then
if [ -f "${WORK_DIR}/package.json" ]; then
echo "Building node-based webapp ..."
cd "${WORK_DIR}" || exit 1
@@ -39,10 +33,4 @@ else
mv "${WORK_DIR}" "${DEST_DIR}"
fi
# One special fix ...
cd "${DEST_DIR}"
for f in $(find . -type f -name '*.htm*'); do
sed -i -e 's#/LACONIC_HOSTED_CONFIG_homepage/#LACONIC_HOSTED_CONFIG_homepage/#g' "$f"
done
exit 0
@@ -10,18 +10,6 @@ if [ "true" == "$CERC_ENABLE_CORS" ]; then
CERC_HTTP_EXTRA_ARGS="$CERC_HTTP_EXTRA_ARGS --cors"
fi
LACONIC_HOSTED_CONFIG_FILE=${LACONIC_HOSTED_CONFIG_FILE}
if [ -z "${LACONIC_HOSTED_CONFIG_FILE}" ]; then
if [ -f "/config/laconic-hosted-config.yml" ]; then
LACONIC_HOSTED_CONFIG_FILE="/config/laconic-hosted-config.yml"
elif [ -f "/config/config.yml" ]; then
LACONIC_HOSTED_CONFIG_FILE="/config/config.yml"
fi
fi
if [ -f "${LACONIC_HOSTED_CONFIG_FILE}" ]; then
/scripts/apply-webapp-config.sh $LACONIC_HOSTED_CONFIG_FILE ${CERC_WEBAPP_FILES_DIR}
fi
/scripts/apply-webapp-config.sh /config/config.yml ${CERC_WEBAPP_FILES_DIR}
/scripts/apply-runtime-env.sh ${CERC_WEBAPP_FILES_DIR}
http-server $CERC_HTTP_EXTRA_ARGS -p ${CERC_LISTEN_PORT:-80} ${CERC_WEBAPP_FILES_DIR}
@@ -1,673 +0,0 @@
# from: https://raw.githubusercontent.com/kubernetes/ingress-nginx/main/deploy/static/provider/kind/deploy.yaml
# via: https://kind.sigs.k8s.io/docs/user/ingress/#ingress-nginx
apiVersion: v1
kind: Namespace
metadata:
labels:
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
name: ingress-nginx
---
apiVersion: v1
automountServiceAccountToken: true
kind: ServiceAccount
metadata:
labels:
app.kubernetes.io/component: controller
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
app.kubernetes.io/version: 1.9.6
name: ingress-nginx
namespace: ingress-nginx
---
apiVersion: v1
kind: ServiceAccount
metadata:
labels:
app.kubernetes.io/component: admission-webhook
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
app.kubernetes.io/version: 1.9.6
name: ingress-nginx-admission
namespace: ingress-nginx
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
labels:
app.kubernetes.io/component: controller
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
app.kubernetes.io/version: 1.9.6
name: ingress-nginx
namespace: ingress-nginx
rules:
- apiGroups:
- ""
resources:
- namespaces
verbs:
- get
- apiGroups:
- ""
resources:
- configmaps
- pods
- secrets
- endpoints
verbs:
- get
- list
- watch
- apiGroups:
- ""
resources:
- services
verbs:
- get
- list
- watch
- apiGroups:
- networking.k8s.io
resources:
- ingresses
verbs:
- get
- list
- watch
- apiGroups:
- networking.k8s.io
resources:
- ingresses/status
verbs:
- update
- apiGroups:
- networking.k8s.io
resources:
- ingressclasses
verbs:
- get
- list
- watch
- apiGroups:
- coordination.k8s.io
resourceNames:
- ingress-nginx-leader
resources:
- leases
verbs:
- get
- update
- apiGroups:
- coordination.k8s.io
resources:
- leases
verbs:
- create
- apiGroups:
- ""
resources:
- events
verbs:
- create
- patch
- apiGroups:
- discovery.k8s.io
resources:
- endpointslices
verbs:
- list
- watch
- get
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
labels:
app.kubernetes.io/component: admission-webhook
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
app.kubernetes.io/version: 1.9.6
name: ingress-nginx-admission
namespace: ingress-nginx
rules:
- apiGroups:
- ""
resources:
- secrets
verbs:
- get
- create
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
labels:
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
app.kubernetes.io/version: 1.9.6
name: ingress-nginx
rules:
- apiGroups:
- ""
resources:
- configmaps
- endpoints
- nodes
- pods
- secrets
- namespaces
verbs:
- list
- watch
- apiGroups:
- coordination.k8s.io
resources:
- leases
verbs:
- list
- watch
- apiGroups:
- ""
resources:
- nodes
verbs:
- get
- apiGroups:
- ""
resources:
- services
verbs:
- get
- list
- watch
- apiGroups:
- networking.k8s.io
resources:
- ingresses
verbs:
- get
- list
- watch
- apiGroups:
- ""
resources:
- events
verbs:
- create
- patch
- apiGroups:
- networking.k8s.io
resources:
- ingresses/status
verbs:
- update
- apiGroups:
- networking.k8s.io
resources:
- ingressclasses
verbs:
- get
- list
- watch
- apiGroups:
- discovery.k8s.io
resources:
- endpointslices
verbs:
- list
- watch
- get
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
labels:
app.kubernetes.io/component: admission-webhook
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
app.kubernetes.io/version: 1.9.6
name: ingress-nginx-admission
rules:
- apiGroups:
- admissionregistration.k8s.io
resources:
- validatingwebhookconfigurations
verbs:
- get
- update
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
labels:
app.kubernetes.io/component: controller
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
app.kubernetes.io/version: 1.9.6
name: ingress-nginx
namespace: ingress-nginx
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: ingress-nginx
subjects:
- kind: ServiceAccount
name: ingress-nginx
namespace: ingress-nginx
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
labels:
app.kubernetes.io/component: admission-webhook
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
app.kubernetes.io/version: 1.9.6
name: ingress-nginx-admission
namespace: ingress-nginx
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: ingress-nginx-admission
subjects:
- kind: ServiceAccount
name: ingress-nginx-admission
namespace: ingress-nginx
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
labels:
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
app.kubernetes.io/version: 1.9.6
name: ingress-nginx
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: ingress-nginx
subjects:
- kind: ServiceAccount
name: ingress-nginx
namespace: ingress-nginx
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
labels:
app.kubernetes.io/component: admission-webhook
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
app.kubernetes.io/version: 1.9.6
name: ingress-nginx-admission
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: ingress-nginx-admission
subjects:
- kind: ServiceAccount
name: ingress-nginx-admission
namespace: ingress-nginx
---
apiVersion: v1
data:
allow-snippet-annotations: "false"
kind: ConfigMap
metadata:
labels:
app.kubernetes.io/component: controller
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
app.kubernetes.io/version: 1.9.6
name: ingress-nginx-controller
namespace: ingress-nginx
---
apiVersion: v1
kind: Service
metadata:
labels:
app.kubernetes.io/component: controller
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
app.kubernetes.io/version: 1.9.6
name: ingress-nginx-controller
namespace: ingress-nginx
spec:
ipFamilies:
- IPv4
ipFamilyPolicy: SingleStack
ports:
- appProtocol: http
name: http
port: 80
protocol: TCP
targetPort: http
- appProtocol: https
name: https
port: 443
protocol: TCP
targetPort: https
selector:
app.kubernetes.io/component: controller
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
type: NodePort
---
apiVersion: v1
kind: Service
metadata:
labels:
app.kubernetes.io/component: controller
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
app.kubernetes.io/version: 1.9.6
name: ingress-nginx-controller-admission
namespace: ingress-nginx
spec:
ports:
- appProtocol: https
name: https-webhook
port: 443
targetPort: webhook
selector:
app.kubernetes.io/component: controller
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
type: ClusterIP
---
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app.kubernetes.io/component: controller
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
app.kubernetes.io/version: 1.9.6
name: ingress-nginx-controller
namespace: ingress-nginx
spec:
minReadySeconds: 0
revisionHistoryLimit: 10
selector:
matchLabels:
app.kubernetes.io/component: controller
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
strategy:
rollingUpdate:
maxUnavailable: 1
type: RollingUpdate
template:
metadata:
labels:
app.kubernetes.io/component: controller
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
app.kubernetes.io/version: 1.9.6
spec:
containers:
- args:
- /nginx-ingress-controller
- --election-id=ingress-nginx-leader
- --controller-class=k8s.io/ingress-nginx
- --ingress-class=nginx
- --configmap=$(POD_NAMESPACE)/ingress-nginx-controller
- --validating-webhook=:8443
- --validating-webhook-certificate=/usr/local/certificates/cert
- --validating-webhook-key=/usr/local/certificates/key
- --watch-ingress-without-class=true
- --publish-status-address=localhost
env:
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
- name: LD_PRELOAD
value: /usr/local/lib/libmimalloc.so
image: registry.k8s.io/ingress-nginx/controller:v1.9.6@sha256:1405cc613bd95b2c6edd8b2a152510ae91c7e62aea4698500d23b2145960ab9c
imagePullPolicy: IfNotPresent
lifecycle:
preStop:
exec:
command:
- /wait-shutdown
livenessProbe:
failureThreshold: 5
httpGet:
path: /healthz
port: 10254
scheme: HTTP
initialDelaySeconds: 10
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 1
name: controller
ports:
- containerPort: 80
hostPort: 80
name: http
protocol: TCP
- containerPort: 443
hostPort: 443
name: https
protocol: TCP
- containerPort: 8443
name: webhook
protocol: TCP
readinessProbe:
failureThreshold: 3
httpGet:
path: /healthz
port: 10254
scheme: HTTP
initialDelaySeconds: 10
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 1
resources:
requests:
cpu: 100m
memory: 90Mi
securityContext:
allowPrivilegeEscalation: false
capabilities:
add:
- NET_BIND_SERVICE
drop:
- ALL
readOnlyRootFilesystem: false
runAsNonRoot: true
runAsUser: 101
seccompProfile:
type: RuntimeDefault
volumeMounts:
- mountPath: /usr/local/certificates/
name: webhook-cert
readOnly: true
dnsPolicy: ClusterFirst
nodeSelector:
ingress-ready: "true"
kubernetes.io/os: linux
serviceAccountName: ingress-nginx
terminationGracePeriodSeconds: 0
tolerations:
- effect: NoSchedule
key: node-role.kubernetes.io/master
operator: Equal
- effect: NoSchedule
key: node-role.kubernetes.io/control-plane
operator: Equal
volumes:
- name: webhook-cert
secret:
secretName: ingress-nginx-admission
---
apiVersion: batch/v1
kind: Job
metadata:
labels:
app.kubernetes.io/component: admission-webhook
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
app.kubernetes.io/version: 1.9.6
name: ingress-nginx-admission-create
namespace: ingress-nginx
spec:
template:
metadata:
labels:
app.kubernetes.io/component: admission-webhook
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
app.kubernetes.io/version: 1.9.6
name: ingress-nginx-admission-create
spec:
containers:
- args:
- create
- --host=ingress-nginx-controller-admission,ingress-nginx-controller-admission.$(POD_NAMESPACE).svc
- --namespace=$(POD_NAMESPACE)
- --secret-name=ingress-nginx-admission
env:
- name: POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
image: registry.k8s.io/ingress-nginx/kube-webhook-certgen:v20231226-1a7112e06@sha256:25d6a5f11211cc5c3f9f2bf552b585374af287b4debf693cacbe2da47daa5084
imagePullPolicy: IfNotPresent
name: create
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop:
- ALL
readOnlyRootFilesystem: true
runAsNonRoot: true
runAsUser: 65532
seccompProfile:
type: RuntimeDefault
nodeSelector:
kubernetes.io/os: linux
restartPolicy: OnFailure
serviceAccountName: ingress-nginx-admission
---
apiVersion: batch/v1
kind: Job
metadata:
labels:
app.kubernetes.io/component: admission-webhook
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
app.kubernetes.io/version: 1.9.6
name: ingress-nginx-admission-patch
namespace: ingress-nginx
spec:
template:
metadata:
labels:
app.kubernetes.io/component: admission-webhook
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
app.kubernetes.io/version: 1.9.6
name: ingress-nginx-admission-patch
spec:
containers:
- args:
- patch
- --webhook-name=ingress-nginx-admission
- --namespace=$(POD_NAMESPACE)
- --patch-mutating=false
- --secret-name=ingress-nginx-admission
- --patch-failure-policy=Fail
env:
- name: POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
image: registry.k8s.io/ingress-nginx/kube-webhook-certgen:v20231226-1a7112e06@sha256:25d6a5f11211cc5c3f9f2bf552b585374af287b4debf693cacbe2da47daa5084
imagePullPolicy: IfNotPresent
name: patch
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop:
- ALL
readOnlyRootFilesystem: true
runAsNonRoot: true
runAsUser: 65532
seccompProfile:
type: RuntimeDefault
nodeSelector:
kubernetes.io/os: linux
restartPolicy: OnFailure
serviceAccountName: ingress-nginx-admission
---
apiVersion: networking.k8s.io/v1
kind: IngressClass
metadata:
labels:
app.kubernetes.io/component: controller
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
app.kubernetes.io/version: 1.9.6
name: nginx
spec:
controller: k8s.io/ingress-nginx
---
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingWebhookConfiguration
metadata:
labels:
app.kubernetes.io/component: admission-webhook
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
app.kubernetes.io/version: 1.9.6
name: ingress-nginx-admission
webhooks:
- admissionReviewVersions:
- v1
clientConfig:
service:
name: ingress-nginx-controller-admission
namespace: ingress-nginx
path: /networking/v1/ingresses
failurePolicy: Fail
matchPolicy: Equivalent
name: validate.nginx.ingress.kubernetes.io
rules:
- apiGroups:
- networking.k8s.io
apiVersions:
- v1
operations:
- CREATE
- UPDATE
resources:
- ingresses
sideEffects: None
@@ -1,3 +0,0 @@
# Container Registry Stack
Host a container image registry
@@ -1,5 +0,0 @@
version: "1.0"
name: container-registry
description: "Container registry stack"
pods:
- container-registry
@@ -1,6 +1,6 @@
# fixturenet-eth
Instructions for deploying a local a geth + lighthouse blockchain "fixturenet" for development and testing purposes using laconic-stack-orchestrator (the installation of which is covered [here](https://git.vdb.to/cerc-io/stack-orchestrator)):
Instructions for deploying a local a geth + lighthouse blockchain "fixturenet" for development and testing purposes using laconic-stack-orchestrator (the installation of which is covered [here](https://github.com/cerc-io/stack-orchestrator)):
## Clone required repositories
@@ -7,11 +7,11 @@ Instructions for deploying a local Laconic blockchain "fixturenet" for developme
**Note:** For building some NPMs, access to the @lirewine repositories is required. If you don't have access, see [this tutorial](/docs/laconicd-fixturenet.md) to run this stack
## 1. Install Laconic Stack Orchestrator
Installation is covered in detail [here](https://git.vdb.to/cerc-io/stack-orchestrator#user-mode) but if you're on Linux and already have docker installed it should be as simple as:
Installation is covered in detail [here](https://github.com/cerc-io/stack-orchestrator#user-mode) but if you're on Linux and already have docker installed it should be as simple as:
```
$ mkdir my-working-dir
$ cd my-working-dir
$ curl -L -o ./laconic-so https://git.vdb.to/cerc-io/stack-orchestrator/releases/download/latest/laconic-so
$ curl -L -o ./laconic-so https://github.com/cerc-io/stack-orchestrator/releases/latest/download/laconic-so
$ chmod +x ./laconic-so
$ export PATH=$PATH:$(pwd) # Or move laconic-so to ~/bin or your favorite on-path directory
```
@@ -0,0 +1,72 @@
# Copyright © 2022-2024 Vulcanize
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
# 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/>.
from stack_orchestrator.util import get_yaml, get_config_file_dir
from stack_orchestrator.deploy.deploy_types import DeployCommandContext
from stack_orchestrator.deploy.deployment_context import DeploymentContext
from pathlib import Path
from shutil import copy
default_spec_file_content = ""
def _stack_config_dir(context: DeploymentContext) -> Path:
return get_config_file_dir().joinpath(context.stack.name)
def _deployment_volume_dir(context: DeploymentContext, volume_name: str) -> Path:
return context.deployment_dir.joinpath("data", volume_name)
def _copy_laconicd_scripts(context: DeploymentContext):
scripts = [
"create-fixturenet.sh",
"export-mykey.sh",
"export-myaddress.sh"
]
destination_dir = _deployment_volume_dir(context, "laconicd-scripts")
for script in scripts:
# ../config/fixturenet-laconicd/
source_file = _stack_config_dir(context).joinpath(script)
copy(source_file, destination_dir)
def _copy_cli_template(context: DeploymentContext):
destination_dir = _deployment_volume_dir(context, "cli-config")
# ../config/fixturenet-laconicd/
source_file = _stack_config_dir(context).joinpath("registry-cli-config-template.yml")
copy(source_file, destination_dir)
def setup(command_context: DeployCommandContext, parameters, extra_args):
pass
def init(command_context: DeployCommandContext):
yaml = get_yaml()
return yaml.load(default_spec_file_content)
def create(context: DeploymentContext, extra_args):
_copy_laconicd_scripts(context)
_copy_cli_template(context)
def get_state(command_context: DeployCommandContext):
pass
def change_state(command_context: DeployCommandContext):
pass
@@ -3,11 +3,11 @@
Instructions for deploying a local Laconic blockchain "fixturenet" for development and testing purposes using laconic-stack-orchestrator.
## 1. Install Laconic Stack Orchestrator
Installation is covered in detail [here](https://git.vdb.to/cerc-io/stack-orchestrator#user-mode) but if you're on Linux and already have docker installed it should be as simple as:
Installation is covered in detail [here](https://github.com/cerc-io/stack-orchestrator#user-mode) but if you're on Linux and already have docker installed it should be as simple as:
```
$ mkdir my-working-dir
$ cd my-working-dir
$ curl -L -o ./laconic-so https://git.vdb.to/cerc-io/stack-orchestrator/releases/download/latest/laconic-so
$ curl -L -o ./laconic-so https://github.com/cerc-io/stack-orchestrator/releases/latest/download/laconic-so
$ chmod +x ./laconic-so
$ export PATH=$PATH:$(pwd) # Or move laconic-so to ~/bin or your favorite on-path directory
```
@@ -1,16 +0,0 @@
# mars
On a fresh Digital Ocean droplet with Ubuntu:
```
git clone https://github.com/cerc-io/stack-orchestrator
cd stack-orchestrator
./scripts/quick-install-linux.sh
```
Read and follow the instructions output from the above output to complete installation, then:
```
laconic-so --stack mars-v2 setup-repositories
laconic-so --stack mars-v2 build-containers
laconic-so --stack mars-v2 deploy up
```
@@ -1,8 +0,0 @@
version: "0.1"
name: mars-v2
repos:
- github.com/mars-protocol/mars-v2-frontend
containers:
- cerc/mars-v2
pods:
- mars-v2
@@ -1,16 +0,0 @@
# mars
On a fresh Digital Ocean droplet with Ubuntu:
```
git clone https://github.com/cerc-io/stack-orchestrator
cd stack-orchestrator
./scripts/quick-install-linux.sh
```
Read and follow the instructions output from the above output to complete installation, then:
```
laconic-so --stack mars setup-repositories
laconic-so --stack mars build-containers
laconic-so --stack mars deploy up
```
@@ -1,8 +0,0 @@
version: "0.1"
name: mars
repos:
- github.com/cerc-io/mars-interface
containers:
- cerc/mars
pods:
- mars
@@ -1,95 +0,0 @@
# MobyMask v3 Demo
Instructions to setup and deploy an end-to-end MobyMask v3 stack (fixturenet-optimism + watchers + web-app) locally using [laconic-stack-orchestrator](/README.md#install)
## Setup
* Clone required repositories:
```bash
laconic-so --stack mobymask-v3-demo setup-repositories --pull
```
* Build the container images:
```bash
laconic-so --stack mobymask-v3-demo build-containers
```
* Install MetaMask Flask extension in a chromium browser from chrome web store and follow the setup instructions
## Deploy
* Create a spec file for the deployment:
```bash
laconic-so --stack mobymask-v3-demo deploy init --output mobymask-v3-demo-spec.yml
```
* Create a deployment from the generated spec file:
```bash
laconic-so --stack mobymask-v3-demo deploy create --spec-file mobymask-v3-demo-spec.yml --deployment-dir mobymask-v3-demo-deployment
```
* Copy over the demo config to place it at an appropriate path:
```bash
cp mobymask-v3-demo-deployment/config/watcher-mobymask-v3-demo/local/config.env mobymask-v3-demo-deployment/
```
### Start the stack
* Start the deployment:
```bash
laconic-so deployment --dir mobymask-v3-demo-deployment start
# Useful ports exposed on host
# 3001: MobyMask v3 watcher 1 GQL endpoint
# 9090: MobyMask v3 watcher 1 relay node endpoint
# 9091: MobyMask v3 watcher 2 relay node endpoint
# 9092: MobyMask v3 watcher 3 relay node endpoint
# 8080: MobyMask snap
# 3004: MobyMask v3 app
```
Note: This may take several minutes as it configures and runs the L1, L2 chains and the watchers; you can follow the progress from containers' logs
* To list and monitor the running containers:
```bash
laconic-so deployment --dir mobymask-v3-demo-deployment ps
# With status
docker ps
# Check logs for a container
docker logs -f <CONTAINER_ID>
```
## Demo
Follow [demo](./demo.md) to try out the MobyMask app
## Clean up
To stop all services running in the background, while preserving data:
```bash
laconic-so deployment --dir mobymask-v3-demo-deployment stop
```
To stop all services and also delete data:
```bash
laconic-so deployment --dir mobymask-v3-demo-deployment stop --delete-volumes
# Also remove the deployment directory
rm -rf mobymask-v3-demo-deployment
```
## Known Issues
* Resource requirements (memory + time) for building the `cerc/foundry` image are on the higher side
* `cerc/optimism-contracts` image is currently based on `cerc/foundry` (Optimism requires foundry installation)
@@ -1,195 +0,0 @@
# Demo
## Setup
* Follow logs and check that all 3 watchers are running in consensus:
```bash
# Follow the logs in three different terminals and keep them running
docker logs -f $(docker ps --filter "name=mobymask-watcher-1" -q)
docker logs -f $(docker ps --filter "name=mobymask-watcher-2" -q)
docker logs -f $(docker ps --filter "name=mobymask-watcher-3" -q)
# Expected output when all three are running in consensus:
# ...
# 2024-02-21T10:42:23.932Z laconic:consensus State changed to 3 (FOLLOWER) with term 286
# 2024-02-21T10:42:23.932Z laconic:consensus State changed to 2 (CANDIDATE) with term 287
# 2024-02-21T10:42:24.406Z laconic:consensus State changed to 1 (LEADER) with term 287
# ...
# At any moment, only one of watchers is the 'LEADER'
```
* In MetaMask, go to settings add a custom network with the following settings:
```bash
# Network name
Local Optimism
# New RPC URL
http://127.0.0.1:8545
# Chain ID
42069
# Currency symbol
ETH
```
Switch to the newly added network
* Import a pre-funded account (using it's private key) for Nitro client in the MobyMask app:
```bash
# PK: 689af8efa8c651a91ad287602527f3af2fe9f6501a7ac4b061667b5a93e037fd
# Address: 0xbDA5747bFD65F08deb54cb465eB87D40e51B197E
```
## Run
### Open MobyMask app
* Copy the generated invite link from MobyMask deployment container logs:
```bash
docker logs -f $(docker ps -a --filter "name=mobymask-1" -q)
# A SIGNED DELEGATION/INVITE LINK:
# ...
# http://127.0.0.1:3004/#/members?invitation=<INVITATION>
```
* Open the invite link in browser where MetaMask was setup
* In the apps debug panel (bottom-right), check from `PEERS` and `GRAPH` tabs that the peer gets connected to relay nodes and watcher peers
* Perform phisher status checks from the app
* First 10 queries are served for free; repeat until the free quota is exhausted
* Same can be seen in the watcher-1's logs (the app makes all the GQL queries to watcher-1):
```bash
# ...
# 2024-02-21T11:01:20.084Z laconic:payments Query rate not configured for "latestBlock", serving free query
# 2024-02-21T11:01:20.084Z vulcanize:resolver latestBlock
# 2024-02-21T11:01:20.108Z laconic:payments Serving a free query to 0x3c9B491ACA5cf17B6C11E39bbFddCA603F387d41
# 2024-02-21T11:01:20.109Z vulcanize:resolver isPhisher 0xf8995f83bbab2bc13fb9a43c6fea4a605616e6f59503f36cbe2ad3abffd0efd3 0xAFA36c47E130d89bcE4470a9030d99f3CEcaD146 TWT:dummyPhisher
# 2024-02-21T11:01:20.113Z vulcanize:indexer isPhisher: db miss, fetching from upstream server
# ...
# After free quota has been exhausted:
# 2024-02-21T11:06:49.311Z laconic:payments Query rate not configured for "latestBlock", serving free query
# 2024-02-21T11:06:49.312Z vulcanize:resolver latestBlock
# 2024-02-21T11:06:49.337Z laconic:payments Rejecting query from 0x3c9B491ACA5cf17B6C11E39bbFddCA603F387d41: Free quota exhausted
```
### Setup app's Nitro node
* Open the `NITRO` tab in debug panel
* Click on `Connect Wallet` button to connect to MetaMask (use the imported account with funds)
* Click on `Connect Snap` to install / connect snap; the watcher Nitro clients should show up in the `NITRO` tab
* Click on `DIRECT FUND` button against watcher-1's Nitro account (`0xAAA6628Ec44A8a742987EF3A114dDFE2D4F7aDCE`) to create a ledger channel with the pre-set amount
* Confirm the tx in MetaMask popup; wait some time for the tx to be confirmed and ledger channel to be created
* The progress can be followed from watcher-1's logs
* The created ledger channel should now be visible in the `NITRO` tab; click on `REFRESH` button otherwise
* Change amount to `10000` and click on `VIRTUAL FUND` button to create a virtual payment channel
* This results in a payment channel between the app and watcher-1
* The payment channel's details should now be visible along with a `PAY` and `VIRTUAL DEFUND` buttons
* Close the debug panel
### Paid queries and mutations
* Perform phisher status checks now that a payment channel has been created
* Amount set in the debug panel's `NITRO` tab is sent along with each request to the watcher
* Check the watcher-1 logs for the received payments:
```bash
# ...
# 2024-02-21T11:35:25.538Z ts-nitro:engine {"msg":"Received message","_msg":{"to":"0xAAA662","from":"0x5D12ac","payloadSummaries":[],"proposalSummaries":[],"payments":[{"amount":50,"channelId":"0x654a85725442828f89b497e3973640613c03b5f5ec47302bfa4402d42c07de30"}],"rejectedObjectives":[]}}
# 2024-02-21T11:35:25.552Z laconic:payments Query rate not configured for "latestBlock", serving free query
# 2024-02-21T11:35:25.553Z vulcanize:resolver latestBlock
# 2024-02-21T11:35:25.557Z laconic:payments Received a payment voucher of 50 from 0x5D12acfbBB1caD65fD61983003a50E0CB6900Fd3
# 2024-02-21T11:35:25.570Z laconic:payments Serving a paid query for 0x5D12acfbBB1caD65fD61983003a50E0CB6900Fd3
# 2024-02-21T11:35:25.570Z vulcanize:resolver isPhisher 0x6a1f0dce967aefd4adf7762c523cde358960236f05734f616ebe69c0abfcb0cc 0xAFA36c47E130d89bcE4470a9030d99f3CEcaD146 TWT:dummyPhisher
# 2024-02-21T11:35:25.580Z vulcanize:indexer isPhisher: db miss, fetching from upstream server
# ...
```
* Rate for mutations is set to `100` in the watcher; go back to the `NITRO` tab in the debug panel and change amount value besides `PAY` button to >=100
* Perform a phisher report
* Enter a new record(s) and click on `Submit batch to p2p network` button
* Among all three watchers running in consensus, whoever is the `LEADER` at time of reporting sends a tx to the chain
* Check all the watchers' logs:
If the payment receiving watcher (1) is leader at that moment:
```bash
# On watcher-1 (payment received + tx sent)
# ...
# 2024-02-21T11:42:55.088Z vulcanize:libp2p-utils [11:42:55] Received a message on mobymask P2P network from peer: 12D3KooWGXxcwevUY7KCfw8fcGhxqxPaiFMGSU4tgJDjE54QGKzf
# 2024-02-21T11:42:55.102Z ts-nitro:engine {"msg":"Received message","_msg":{"to":"0xAAA662","from":"0x5D12ac","payloadSummaries":[],"proposalSummaries":[],"payments":[{"amount":150,"channelId":"0x654a85725442828f89b497e3973640613c03b5f5ec47302bfa4402d42c07de30"}],"rejectedObjectives":[]}}
# 2024-02-21T11:42:55.115Z laconic:payments Received a payment voucher of 100 from 0x5D12acfbBB1caD65fD61983003a50E0CB6900Fd3
# 2024-02-21T11:42:55.115Z vulcanize:libp2p-utils Payment received for a mutation request from 0x5D12acfbBB1caD65fD61983003a50E0CB6900Fd3
# 2024-02-21T11:42:59.115Z vulcanize:libp2p-utils Transaction receipt for invoke message {
# to: '0xAFA36c47E130d89bcE4470a9030d99f3CEcaD146',
# blockNumber: 4638,
# blockHash: '0x23a42bc2ae43771c62b0d59cc48b5858e6e2e488953527ba6a9f5119ae72b42a',
# transactionHash: '0xb61cfdfd0ffe937a191a230e1355b9bc5cdd32507f7b4f24a8e6356adf089b64',
# effectiveGasPrice: '1500000050',
# gasUsed: '136450'
# }
# ...
# On other watchers (payment not received + tx not sent)
...
# 2024-02-21T11:42:50.329Z laconic:consensus State changed to 3 (FOLLOWER) with term 478
# 2024-02-21T11:42:55.089Z vulcanize:libp2p-utils [11:42:55] Received a message on mobymask P2P network from peer: 12D3KooWGXxcwevUY7KCfw8fcGhxqxPaiFMGSU4tgJDjE54QGKzf
# 2024-02-21T11:42:55.096Z vulcanize:libp2p-utils Not a leader, skipped sending L2 tx
# 2024-02-21T11:43:05.095Z vulcanize:libp2p-utils Payment not received
# ...
```
If the payment receiving watcher (1) is NOT leader at that moment:
```bash
# On watcher 1 (payment received + tx not sent)
# ...
# 2024-02-21T11:46:52.049Z vulcanize:libp2p-utils [11:46:52] Received a message on mobymask P2P network from peer: 12D3KooWGXxcwevUY7KCfw8fcGhxqxPaiFMGSU4tgJDjE54QGKzf
# 2024-02-21T11:46:52.051Z vulcanize:libp2p-utils Not a leader, skipped sending L2 tx
# 2024-02-21T11:46:52.074Z ts-nitro:engine {"msg":"Received message","_msg":{"to":"0xAAA662","from":"0x5D12ac","payloadSummaries":[],"proposalSummaries":[],"payments":[{"amount":450,"channelId":"0x654a85725442828f89b497e3973640613c03b5f5ec47302bfa4402d42c07de30"}],"rejectedObjectives":[]}}
# 2024-02-21T11:46:52.097Z laconic:payments Received a payment voucher of 100 from 0x5D12acfbBB1caD65fD61983003a50E0CB6900Fd3
# 2024-02-21T11:46:52.097Z vulcanize:libp2p-utils Payment received for a mutation request from 0x5D12acfbBB1caD65fD61983003a50E0CB6900Fd3
# ...
# On the leader watcher (payment not received + tx sent)
# ...
# 2024-02-21T11:46:40.111Z vulcanize:libp2p-utils Payment not received
# 2024-02-21T11:46:52.048Z vulcanize:libp2p-utils [11:46:52] Received a message on mobymask P2P network from peer: 12D3KooWGXxcwevUY7KCfw8fcGhxqxPaiFMGSU4tgJDjE54QGKzf
# 2024-02-21T11:46:56.048Z vulcanize:libp2p-utils Transaction receipt for invoke message {
# to: '0xAFA36c47E130d89bcE4470a9030d99f3CEcaD146',
# blockNumber: 4757,
# blockHash: '0x859aa54cb02e8a3f910a01b85c2a7bf9bff7540e83018e7e846f87ca1770e55e',
# transactionHash: '0x92f087e4b6ac5604c9d4ecd823d526ca5f8f1bf5c2a92861d6b0f69bd899ba83',
# effectiveGasPrice: '1500000050',
# gasUsed: '136438'
# }
```
* Check phisher status for the reported phishers to confirm state update
## Clean up
* From the `NITRO` tab in debug panel, perform `VIRTUAL DEFUND` and `DIRECT DEFUND` (in order) for any payment channels created
* In the browser's console, delete all indexedDBs:
```bash
await clearNodeStorage()
```
* Remove the snap from MetaMask flask extension
@@ -1,68 +0,0 @@
# Copyright © 2023 Vulcanize
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
# 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/>.
from stack_orchestrator.deploy.deployment_context import DeploymentContext
from ruamel.yaml import YAML
def create(context: DeploymentContext, extra_args):
fixturenet_eth_compose_file = context.deployment_dir.joinpath('compose', 'docker-compose-fixturenet-eth.yml')
with open(fixturenet_eth_compose_file, 'r') as yaml_file:
yaml = YAML()
yaml_data = yaml.load(yaml_file)
new_script = '../config/fixturenet-optimism/run-geth.sh:/opt/testnet/run.sh'
if new_script not in yaml_data['services']['fixturenet-eth-geth-1']['volumes']:
yaml_data['services']['fixturenet-eth-geth-1']['volumes'].append(new_script)
with open(fixturenet_eth_compose_file, 'w') as yaml_file:
yaml = YAML()
yaml.dump(yaml_data, yaml_file)
# load fixturenet-optimism compose file
fixturenet_optimism_compose_file = context.deployment_dir.joinpath(
"compose",
"docker-compose-fixturenet-optimism.yml"
)
with open(fixturenet_optimism_compose_file, 'r') as yaml_file:
yaml = YAML()
yaml_data = yaml.load(yaml_file)
# mount the funding script to volumes
fund_accounts_script = (
'../config/watcher-mobymask-v3-demo/local/fund-accounts-on-l2.sh'
':/app/packages/contracts-bedrock/fund-accounts-on-l2.sh'
)
yaml_data['services']['fixturenet-optimism-contracts']['volumes'].append(fund_accounts_script)
# update command to run the script
yaml_data['services']['fixturenet-optimism-contracts']['command'] = (
'"./wait-for-it.sh -h ${CERC_L1_HOST:-$${DEFAULT_CERC_L1_HOST}}'
' -p ${CERC_L1_PORT:-$${DEFAULT_CERC_L1_PORT}} -s -t 60'
' -- ./deploy-contracts.sh && ./fund-accounts-on-l2.sh"'
)
# update port mapping for op-geth: 0.0.0.0:8545:8545
existing_ports = yaml_data['services']['op-geth']['ports']
new_ports = ["0.0.0.0:8545:8545" if "8545" in s else s for s in existing_ports]
yaml_data['services']['op-geth']['ports'] = new_ports
with open(fixturenet_optimism_compose_file, 'w') as yaml_file:
yaml = YAML()
yaml.dump(yaml_data, yaml_file)
return None
@@ -1,47 +0,0 @@
version: "1.0"
description: "MobyMask v3 demo stack"
name: mobymask-v3-demo
repos:
# fixturenet repos
- git.vdb.to/cerc-io/go-ethereum@v1.11.6-statediff-v5
- git.vdb.to/cerc-io/lighthouse
- github.com/dboreham/foundry
- github.com/ethereum-optimism/optimism@op-node/v1.3.0
- github.com/ethereum-optimism/op-geth@v1.101304.0
# nitro repo
- github.com/cerc-io/ts-nitro@v0.1.15
# mobymask watcher repos
- github.com/cerc-io/mobymask-v2-watcher-ts@v0.2.4
- github.com/cerc-io/MobyMask@v0.1.3
# mobymask app repos
- github.com/cerc-io/mobymask-snap
- github.com/cerc-io/mobymask-ui@v0.2.2
containers:
# fixturenet images
- cerc/go-ethereum
- cerc/lighthouse
- cerc/lighthouse-cli
- cerc/fixturenet-eth-genesis
- cerc/fixturenet-eth-geth
- cerc/fixturenet-eth-lighthouse
- cerc/foundry
- cerc/optimism-contracts
- cerc/optimism-op-node
- cerc/optimism-l2geth
- cerc/optimism-op-batcher
- cerc/optimism-op-proposer
# nitro contract deployment image
- cerc/nitro-contracts
# mobymask watcher images
- cerc/watcher-mobymask-v3
- cerc/mobymask
# mobymask app images
- cerc/mobymask-snap
- cerc/mobymask-ui
pods:
- fixturenet-eth
- fixturenet-optimism
- nitro-contracts
- watcher-mobymask-v3-demo
- mobymask-snap
- mobymask-app-v3-demo
@@ -75,7 +75,7 @@ Create and update an env file to be used in the next step ([defaults](../../conf
# Uses a generated peer id if not set (disables consensus)
CERC_PEER_ID=
# Enable payments to upstream ETH server
# Disable payments to upstream ETH server
CERC_ENABLE_UPSTREAM_PAYMENTS=false
```
@@ -4,7 +4,7 @@ The MobyMask watcher is a Laconic Network component that provides efficient acce
## Deploy the MobyMask Watcher
The instructions below show how to deploy a MobyMask watcher using laconic-stack-orchestrator (the installation of which is covered [here](https://git.vdb.to/cerc-io/stack-orchestrator#install)).
The instructions below show how to deploy a MobyMask watcher using laconic-stack-orchestrator (the installation of which is covered [here](https://github.com/cerc-io/stack-orchestrator#install)).
This deployment expects that ipld-eth-server's endpoints are available on the local machine at http://ipld-eth-server.example.com:8083/graphql and http://ipld-eth-server.example.com:8082. More advanced configurations are supported by modifying the watcher's [config file](../../config/watcher-mobymask/mobymask-watcher.toml).
@@ -112,7 +112,7 @@ Place the pre-configured watcher alerts rules in Grafana provisioning directory:
Update the alerting contact points config (`monitoring-watchers-deployment/config/monitoring/grafana/provisioning/alerting/contactpoints.yml`) with desired contact points
Add corresponding routes to the notification policies config (`monitoring-watchers-deployment/config/monitoring/grafana/provisioning/alerting/policies.yml`) with appropriate object-matchers:
Add corresponding routes to the notification policies config (`monitoring-watchers-deployment/monitoring/grafana/provisioning/alerting/policies.yaml`) with appropriate object-matchers:
```yml
...
@@ -1,10 +0,0 @@
# ping-pub
Experimental block explorer for laconic
```
laconic-so --stack ping-pub setup-repositories
laconic-so --stack ping-pub build-containers
laconic-so --stack ping-pub deploy init --output ping-pub-spec.yml --map-ports-to-host localhost-same
laconic-so --stack ping-pub deploy create --spec-file ping-pub-spec.yml --deployment-dir pp-deployment
laconic-so deployment --dir pp-deployment start
```
@@ -1,9 +0,0 @@
version: "0.1"
name: ping-pub
repos:
# fork, but only for config & Dockerfile reasonsb
- github.com/LaconicNetwork/explorer@laconic
containers:
- cerc/ping-pub
pods:
- ping-pub
@@ -1,10 +0,0 @@
version: "1.0"
name: snowballtools-base-backend
description: "snowballtools-base-backend"
repos:
- github.com/snowball-tools/snowballtools-base
containers:
- cerc/webapp-base
- cerc/snowballtools-base-backend
pods:
- snowballtools-base-backend
@@ -1,3 +0,0 @@
# Test Database Stack
A stack with a database for test/demo purposes.
@@ -1,9 +0,0 @@
version: "1.0"
name: test
description: "A test database stack"
repos:
containers:
- cerc/test-database-container
- cerc/test-database-client
pods:
- test-database
@@ -2,10 +2,10 @@ version: "1.0"
name: webapp-deployer-backend
description: "Deployer for webapps"
repos:
- git.vdb.to/telackey/webapp-deployment-status-api
- git.vdb.to:telackey/webapp-deployment-status-api
containers:
- cerc/webapp-deployer-backend
pods:
- name: webapp-deployer-backend
repository: git.vdb.to/telackey/webapp-deployment-status-api
repository: git.vdb.to:telackey/webapp-deployment-status-api
path: ./
+24 -51
View File
@@ -27,7 +27,6 @@ from stack_orchestrator.opts import opts
from stack_orchestrator.util import (get_stack_file_path, get_parsed_deployment_spec, get_parsed_stack_config,
global_options, get_yaml, get_pod_list, get_pod_file_path, pod_has_scripts,
get_pod_script_paths, get_plugin_code_paths, error_exit, env_var_map_from_file)
from stack_orchestrator.deploy.spec import Spec
from stack_orchestrator.deploy.deploy_types import LaconicStackSetupCommand
from stack_orchestrator.deploy.deployer_factory import getDeployerConfigGenerator
from stack_orchestrator.deploy.deployment_context import DeploymentContext
@@ -112,7 +111,6 @@ def _create_bind_dir_if_relative(volume, path_string, compose_dir):
# See: https://stackoverflow.com/questions/45699189/editing-docker-compose-yml-with-pyyaml
def _fixup_pod_file(pod, spec, compose_dir):
deployment_type = spec[constants.deploy_to_key]
# Fix up volumes
if "volumes" in spec:
spec_volumes = spec["volumes"]
@@ -121,34 +119,27 @@ def _fixup_pod_file(pod, spec, compose_dir):
for volume in pod_volumes.keys():
if volume in spec_volumes:
volume_spec = spec_volumes[volume]
if volume_spec:
volume_spec_fixedup = volume_spec if Path(volume_spec).is_absolute() else f".{volume_spec}"
_create_bind_dir_if_relative(volume, volume_spec, compose_dir)
# this is Docker specific
if spec.is_docker_deployment():
new_volume_spec = {
"driver": "local",
"driver_opts": {
"type": "none",
"device": volume_spec_fixedup,
"o": "bind"
}
}
pod["volumes"][volume] = new_volume_spec
volume_spec_fixedup = volume_spec if Path(volume_spec).is_absolute() else f".{volume_spec}"
_create_bind_dir_if_relative(volume, volume_spec, compose_dir)
new_volume_spec = {"driver": "local",
"driver_opts": {
"type": "none",
"device": volume_spec_fixedup,
"o": "bind"
}
}
pod["volumes"][volume] = new_volume_spec
# Fix up configmaps
if constants.configmaps_key in spec:
if spec.is_kubernetes_deployment():
spec_cfgmaps = spec[constants.configmaps_key]
if "volumes" in pod:
pod_volumes = pod[constants.volumes_key]
for volume in pod_volumes.keys():
if volume in spec_cfgmaps:
volume_cfg = spec_cfgmaps[volume]
# Just make the dir (if necessary)
_create_bind_dir_if_relative(volume, volume_cfg, compose_dir)
else:
print(f"Warning: ConfigMaps not supported for {deployment_type}")
if "configmaps" in spec:
spec_cfgmaps = spec["configmaps"]
if "volumes" in pod:
pod_volumes = pod["volumes"]
for volume in pod_volumes.keys():
if volume in spec_cfgmaps:
volume_cfg = spec_cfgmaps[volume]
# Just make the dir (if necessary)
_create_bind_dir_if_relative(volume, volume_cfg, compose_dir)
# Fix up ports
if "network" in spec and "ports" in spec["network"]:
@@ -332,7 +323,7 @@ def init_operation(deploy_command_context, stack, deployer_type, config,
if image_registry is None:
error_exit("--image-registry must be supplied with --deploy-to k8s")
spec_file_content.update({constants.kube_config_key: kube_config})
spec_file_content.update({constants.image_registry_key: image_registry})
spec_file_content.update({constants.image_resigtry_key: image_registry})
else:
# Check for --kube-config supplied for non-relevant deployer types
if kube_config is not None:
@@ -367,16 +358,10 @@ def init_operation(deploy_command_context, stack, deployer_type, config,
volume_descriptors = {}
configmap_descriptors = {}
for named_volume in named_volumes["rw"]:
if "k8s" in deployer_type:
volume_descriptors[named_volume] = None
else:
volume_descriptors[named_volume] = f"./data/{named_volume}"
volume_descriptors[named_volume] = f"./data/{named_volume}"
for named_volume in named_volumes["ro"]:
if "k8s" in deployer_type:
if "config" in named_volume:
configmap_descriptors[named_volume] = f"./configmaps/{named_volume}"
else:
volume_descriptors[named_volume] = None
if "k8s" in deployer_type and "config" in named_volume:
configmap_descriptors[named_volume] = f"./data/{named_volume}"
else:
volume_descriptors[named_volume] = f"./data/{named_volume}"
if volume_descriptors:
@@ -421,17 +406,6 @@ def _create_deployment_file(deployment_dir: Path):
output_file.write(f"{constants.cluster_id_key}: {cluster}\n")
def _check_volume_definitions(spec):
if spec.is_kubernetes_deployment():
for volume_name, volume_path in spec.get_volumes().items():
if volume_path:
if not os.path.isabs(volume_path):
raise Exception(
f"Relative path {volume_path} for volume {volume_name} not "
f"supported for deployment type {spec.get_deployment_type()}"
)
@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")
@@ -447,8 +421,7 @@ def create(ctx, spec_file, deployment_dir, network_dir, initial_peers):
# The init command's implementation is in a separate function so that we can
# call it from other commands, bypassing the click decoration stuff
def create_operation(deployment_command_context, spec_file, deployment_dir, network_dir, initial_peers):
parsed_spec = Spec(os.path.abspath(spec_file), get_parsed_deployment_spec(spec_file))
_check_volume_definitions(parsed_spec)
parsed_spec = get_parsed_deployment_spec(spec_file)
stack_name = parsed_spec["stack"]
deployment_type = parsed_spec[constants.deploy_to_key]
stack_file = get_stack_file_path(stack_name)
+1 -1
View File
@@ -46,7 +46,7 @@ def push_images_operation(command_context: DeployCommandContext, deployment_cont
cluster_context = command_context.cluster_context
images: Set[str] = images_for_deployment(cluster_context.compose_files)
# Tag the images for the remote repo
remote_repo_url = deployment_context.spec.obj[constants.image_registry_key]
remote_repo_url = deployment_context.spec.obj[constants.image_resigtry_key]
docker = DockerClient()
for image in images:
if _image_needs_pushed(image):
+22 -138
View File
@@ -21,42 +21,13 @@ from typing import Any, List, Set
from stack_orchestrator.opts import opts
from stack_orchestrator.util import env_var_map_from_file
from stack_orchestrator.deploy.k8s.helpers import named_volumes_from_pod_files, volume_mounts_for_service, volumes_for_pod_files
from stack_orchestrator.deploy.k8s.helpers import get_kind_pv_bind_mount_path
from stack_orchestrator.deploy.k8s.helpers import envs_from_environment_variables_map, envs_from_compose_file, merge_envs
from stack_orchestrator.deploy.k8s.helpers import get_node_pv_mount_path
from stack_orchestrator.deploy.k8s.helpers import envs_from_environment_variables_map
from stack_orchestrator.deploy.deploy_util import parsed_pod_files_map_from_file_names, images_for_deployment
from stack_orchestrator.deploy.deploy_types import DeployEnvVars
from stack_orchestrator.deploy.spec import Spec, Resources, ResourceLimits
from stack_orchestrator.deploy.spec import Spec
from stack_orchestrator.deploy.images import remote_tag_for_image
DEFAULT_VOLUME_RESOURCES = Resources({
"reservations": {"storage": "2Gi"}
})
DEFAULT_CONTAINER_RESOURCES = Resources({
"reservations": {"cpus": "0.1", "memory": "200M"},
"limits": {"cpus": "1.0", "memory": "2000M"},
})
def to_k8s_resource_requirements(resources: Resources) -> client.V1ResourceRequirements:
def to_dict(limits: ResourceLimits):
if not limits:
return None
ret = {}
if limits.cpus:
ret["cpu"] = str(limits.cpus)
if limits.memory:
ret["memory"] = f"{int(limits.memory / (1000 * 1000))}M"
if limits.storage:
ret["storage"] = f"{int(limits.storage / (1000 * 1000))}M"
return ret
return client.V1ResourceRequirements(
requests=to_dict(resources.reservations),
limits=to_dict(resources.limits)
)
class ClusterInfo:
parsed_pod_yaml_map: Any
@@ -78,30 +49,7 @@ class ClusterInfo:
if (opts.o.debug):
print(f"Env vars: {self.environment_variables.map}")
def get_nodeport(self):
for pod_name in self.parsed_pod_yaml_map:
pod = self.parsed_pod_yaml_map[pod_name]
services = pod["services"]
for service_name in services:
service_info = services[service_name]
if "ports" in service_info:
port = int(service_info["ports"][0])
if opts.o.debug:
print(f"service port: {port}")
service = client.V1Service(
metadata=client.V1ObjectMeta(name=f"{self.app_name}-nodeport"),
spec=client.V1ServiceSpec(
type="NodePort",
ports=[client.V1ServicePort(
port=port,
target_port=port
)],
selector={"app": self.app_name}
)
)
return service
def get_ingress(self, use_tls=False):
def get_ingress(self):
# No ingress for a deployment that has no http-proxy defined, for now
http_proxy_info_list = self.spec.get_http_proxy()
ingress = None
@@ -116,7 +64,7 @@ class ClusterInfo:
tls = [client.V1IngressTLS(
hosts=[host_name],
secret_name=f"{self.app_name}-tls"
)] if use_tls else None
)]
paths = []
for route in http_proxy_info["routes"]:
path = route["path"]
@@ -187,40 +135,26 @@ class ClusterInfo:
result = []
spec_volumes = self.spec.get_volumes()
named_volumes = named_volumes_from_pod_files(self.parsed_pod_yaml_map)
resources = self.spec.get_volume_resources()
if not resources:
resources = DEFAULT_VOLUME_RESOURCES
if opts.o.debug:
print(f"Spec Volumes: {spec_volumes}")
print(f"Named Volumes: {named_volumes}")
print(f"Resources: {resources}")
for volume_name, volume_path in spec_volumes.items():
for volume_name in spec_volumes:
if volume_name not in named_volumes:
if opts.o.debug:
print(f"{volume_name} not in pod files")
continue
labels = {
"app": self.app_name,
"volume-label": f"{self.app_name}-{volume_name}"
}
if volume_path:
storage_class_name = "manual"
k8s_volume_name = f"{self.app_name}-{volume_name}"
else:
# These will be auto-assigned.
storage_class_name = None
k8s_volume_name = None
spec = client.V1PersistentVolumeClaimSpec(
access_modes=["ReadWriteOnce"],
storage_class_name=storage_class_name,
resources=to_k8s_resource_requirements(resources),
volume_name=k8s_volume_name
storage_class_name="manual",
resources=client.V1ResourceRequirements(
requests={"storage": "2Gi"}
),
volume_name=f"{self.app_name}-{volume_name}"
)
pvc = client.V1PersistentVolumeClaim(
metadata=client.V1ObjectMeta(name=f"{self.app_name}-{volume_name}", labels=labels),
spec=spec
metadata=client.V1ObjectMeta(name=f"{self.app_name}-{volume_name}",
labels={"volume-label": f"{self.app_name}-{volume_name}"}),
spec=spec,
)
result.append(pvc)
return result
@@ -258,35 +192,16 @@ class ClusterInfo:
result = []
spec_volumes = self.spec.get_volumes()
named_volumes = named_volumes_from_pod_files(self.parsed_pod_yaml_map)
resources = self.spec.get_volume_resources()
if not resources:
resources = DEFAULT_VOLUME_RESOURCES
for volume_name, volume_path in spec_volumes.items():
# We only need to create a volume if it is fully qualified HostPath.
# Otherwise, we create the PVC and expect the node to allocate the volume for us.
if not volume_path:
if opts.o.debug:
print(f"{volume_name} does not require an explicit PersistentVolume, since it is not a bind-mount.")
continue
for volume_name in spec_volumes:
if volume_name not in named_volumes:
if opts.o.debug:
print(f"{volume_name} not in pod files")
continue
if not os.path.isabs(volume_path):
print(f"WARNING: {volume_name}:{volume_path} is not absolute, cannot bind volume.")
continue
if self.spec.is_kind_deployment():
host_path = client.V1HostPathVolumeSource(path=get_kind_pv_bind_mount_path(volume_name))
else:
host_path = client.V1HostPathVolumeSource(path=volume_path)
spec = client.V1PersistentVolumeSpec(
storage_class_name="manual",
access_modes=["ReadWriteOnce"],
capacity=to_k8s_resource_requirements(resources).requests,
host_path=host_path
capacity={"storage": "2Gi"},
host_path=client.V1HostPathVolumeSource(path=get_node_pv_mount_path(volume_name))
)
pv = client.V1PersistentVolume(
metadata=client.V1ObjectMeta(name=f"{self.app_name}-{volume_name}",
@@ -299,9 +214,6 @@ class ClusterInfo:
# TODO: put things like image pull policy into an object-scope struct
def get_deployment(self, image_pull_policy: str = None):
containers = []
resources = self.spec.get_container_resources()
if not resources:
resources = DEFAULT_CONTAINER_RESOURCES
for pod_name in self.parsed_pod_yaml_map:
pod = self.parsed_pod_yaml_map[pod_name]
services = pod["services"]
@@ -314,13 +226,6 @@ class ClusterInfo:
if opts.o.debug:
print(f"image: {image}")
print(f"service port: {port}")
merged_envs = merge_envs(
envs_from_compose_file(
service_info["environment"]), self.environment_variables.map
) if "environment" in service_info else self.environment_variables.map
envs = envs_from_environment_variables_map(merged_envs)
if opts.o.debug:
print(f"Merged envs: {envs}")
# Re-write the image tag for remote deployment
image_to_use = remote_tag_for_image(
image, self.spec.get_image_registry()) if self.spec.get_image_registry() is not None else image
@@ -329,40 +234,19 @@ class ClusterInfo:
name=container_name,
image=image_to_use,
image_pull_policy=image_pull_policy,
env=envs,
env=envs_from_environment_variables_map(self.environment_variables.map),
ports=[client.V1ContainerPort(container_port=port)],
volume_mounts=volume_mounts,
security_context=client.V1SecurityContext(
privileged=self.spec.get_privileged(),
capabilities=client.V1Capabilities(
add=self.spec.get_capabilities()
) if self.spec.get_capabilities() else None
resources=client.V1ResourceRequirements(
requests={"cpu": "100m", "memory": "200Mi"},
limits={"cpu": "1000m", "memory": "2000Mi"},
),
resources=to_k8s_resource_requirements(resources),
)
containers.append(container)
volumes = volumes_for_pod_files(self.parsed_pod_yaml_map, self.spec, self.app_name)
image_pull_secrets = [client.V1LocalObjectReference(name="laconic-registry")]
annotations = None
labels = {"app": self.app_name}
if self.spec.get_annotations():
annotations = {}
for key, value in self.spec.get_annotations().items():
for service_name in services:
annotations[key.replace("{name}", service_name)] = value
if self.spec.get_labels():
for key, value in self.spec.get_labels().items():
for service_name in services:
labels[key.replace("{name}", service_name)] = value
template = client.V1PodTemplateSpec(
metadata=client.V1ObjectMeta(
annotations=annotations,
labels=labels
),
metadata=client.V1ObjectMeta(labels={"app": self.app_name}),
spec=client.V1PodSpec(containers=containers, image_pull_secrets=image_pull_secrets, volumes=volumes),
)
spec = client.V1DeploymentSpec(
+55 -118
View File
@@ -20,9 +20,7 @@ from kubernetes import client, config
from stack_orchestrator import constants
from stack_orchestrator.deploy.deployer import Deployer, DeployerConfigGenerator
from stack_orchestrator.deploy.k8s.helpers import create_cluster, destroy_cluster, load_images_into_kind
from stack_orchestrator.deploy.k8s.helpers import install_ingress_for_kind, wait_for_ingress_in_kind
from stack_orchestrator.deploy.k8s.helpers import pods_in_deployment, containers_in_pod, log_stream_from_string
from stack_orchestrator.deploy.k8s.helpers import generate_kind_config
from stack_orchestrator.deploy.k8s.helpers import pods_in_deployment, log_stream_from_string, generate_kind_config
from stack_orchestrator.deploy.k8s.cluster_info import ClusterInfo
from stack_orchestrator.opts import opts
from stack_orchestrator.deploy.deployment_context import DeploymentContext
@@ -90,16 +88,6 @@ class K8sDeployer(Deployer):
if opts.o.debug:
print(f"Sending this pv: {pv}")
if not opts.o.dry_run:
try:
pv_resp = self.core_api.read_persistent_volume(name=pv.metadata.name)
if pv_resp:
if opts.o.debug:
print("PVs already present:")
print(f"{pv_resp}")
continue
except: # noqa: E722
pass
pv_resp = self.core_api.create_persistent_volume(body=pv)
if opts.o.debug:
print("PVs created:")
@@ -112,17 +100,6 @@ class K8sDeployer(Deployer):
print(f"Sending this pvc: {pvc}")
if not opts.o.dry_run:
try:
pvc_resp = self.core_api.read_namespaced_persistent_volume_claim(
name=pvc.metadata.name, namespace=self.k8s_namespace)
if pvc_resp:
if opts.o.debug:
print("PVCs already present:")
print(f"{pvc_resp}")
continue
except: # noqa: E722
pass
pvc_resp = self.core_api.create_namespaced_persistent_volume_claim(body=pvc, namespace=self.k8s_namespace)
if opts.o.debug:
print("PVCs created:")
@@ -177,80 +154,60 @@ class K8sDeployer(Deployer):
# Ensure the referenced containers are copied into kind
load_images_into_kind(self.kind_cluster_name, self.cluster_info.image_set)
self.connect_api()
if self.is_kind():
# Now configure an ingress controller (not installed by default in kind)
install_ingress_for_kind()
# Wait for ingress to start (deployment provisioning will fail unless this is done)
wait_for_ingress_in_kind()
else:
print("Dry run mode enabled, skipping k8s API connect")
self._create_volume_data()
self._create_deployment()
# Note: at present we don't support tls for kind (and enabling tls causes errors)
ingress: client.V1Ingress = self.cluster_info.get_ingress(use_tls=not self.is_kind())
if ingress:
if opts.o.debug:
print(f"Sending this ingress: {ingress}")
if not opts.o.dry_run:
ingress_resp = self.networking_api.create_namespaced_ingress(
namespace=self.k8s_namespace,
body=ingress
)
if opts.o.debug:
print("Ingress created:")
print(f"{ingress_resp}")
else:
if opts.o.debug:
print("No ingress configured")
if not self.is_kind():
ingress: client.V1Ingress = self.cluster_info.get_ingress()
nodeport: client.V1Service = self.cluster_info.get_nodeport()
if nodeport:
if opts.o.debug:
print(f"Sending this nodeport: {nodeport}")
if not opts.o.dry_run:
nodeport_resp = self.core_api.create_namespaced_service(
namespace=self.k8s_namespace,
body=nodeport
)
if ingress:
if opts.o.debug:
print("NodePort created:")
print(f"{nodeport_resp}")
print(f"Sending this ingress: {ingress}")
if not opts.o.dry_run:
ingress_resp = self.networking_api.create_namespaced_ingress(
namespace=self.k8s_namespace,
body=ingress
)
if opts.o.debug:
print("Ingress created:")
print(f"{ingress_resp}")
else:
if opts.o.debug:
print("No ingress configured")
def down(self, timeout, volumes): # noqa: C901
self.connect_api()
# Delete the k8s objects
if volumes:
# Create the host-path-mounted PVs for this deployment
pvs = self.cluster_info.get_pvs()
for pv in pvs:
# Create the host-path-mounted PVs for this deployment
pvs = self.cluster_info.get_pvs()
for pv in pvs:
if opts.o.debug:
print(f"Deleting this pv: {pv}")
try:
pv_resp = self.core_api.delete_persistent_volume(name=pv.metadata.name)
if opts.o.debug:
print(f"Deleting this pv: {pv}")
try:
pv_resp = self.core_api.delete_persistent_volume(name=pv.metadata.name)
if opts.o.debug:
print("PV deleted:")
print(f"{pv_resp}")
except client.exceptions.ApiException as e:
_check_delete_exception(e)
print("PV deleted:")
print(f"{pv_resp}")
except client.exceptions.ApiException as e:
_check_delete_exception(e)
# Figure out the PVCs for this deployment
pvcs = self.cluster_info.get_pvcs()
for pvc in pvcs:
# Figure out the PVCs for this deployment
pvcs = self.cluster_info.get_pvcs()
for pvc in pvcs:
if opts.o.debug:
print(f"Deleting this pvc: {pvc}")
try:
pvc_resp = self.core_api.delete_namespaced_persistent_volume_claim(
name=pvc.metadata.name, namespace=self.k8s_namespace
)
if opts.o.debug:
print(f"Deleting this pvc: {pvc}")
try:
pvc_resp = self.core_api.delete_namespaced_persistent_volume_claim(
name=pvc.metadata.name, namespace=self.k8s_namespace
)
if opts.o.debug:
print("PVCs deleted:")
print(f"{pvc_resp}")
except client.exceptions.ApiException as e:
_check_delete_exception(e)
print("PVCs deleted:")
print(f"{pvc_resp}")
except client.exceptions.ApiException as e:
_check_delete_exception(e)
# Figure out the ConfigMaps for this deployment
cfg_maps = self.cluster_info.get_configmaps()
@@ -288,34 +245,20 @@ class K8sDeployer(Deployer):
except client.exceptions.ApiException as e:
_check_delete_exception(e)
ingress: client.V1Ingress = self.cluster_info.get_ingress(use_tls=not self.is_kind())
if ingress:
if opts.o.debug:
print(f"Deleting this ingress: {ingress}")
try:
self.networking_api.delete_namespaced_ingress(
name=ingress.metadata.name, namespace=self.k8s_namespace
)
except client.exceptions.ApiException as e:
_check_delete_exception(e)
else:
if opts.o.debug:
print("No ingress to delete")
nodeport: client.V1Service = self.cluster_info.get_nodeport()
if nodeport:
if opts.o.debug:
print(f"Deleting this nodeport: {ingress}")
try:
self.core_api.delete_namespaced_service(
namespace=self.k8s_namespace,
name=nodeport.metadata.name
)
except client.exceptions.ApiException as e:
_check_delete_exception(e)
else:
if opts.o.debug:
print("No nodeport to delete")
if not self.is_kind():
ingress: client.V1Ingress = self.cluster_info.get_ingress()
if ingress:
if opts.o.debug:
print(f"Deleting this ingress: {ingress}")
try:
self.networking_api.delete_namespaced_ingress(
name=ingress.metadata.name, namespace=self.k8s_namespace
)
except client.exceptions.ApiException as e:
_check_delete_exception(e)
else:
if opts.o.debug:
print("No ingress to delete")
if self.is_kind():
# Destroy the kind cluster
@@ -416,15 +359,9 @@ class K8sDeployer(Deployer):
log_data = "******* Pods not running ********\n"
else:
k8s_pod_name = pods[0]
containers = containers_in_pod(self.core_api, k8s_pod_name)
# If the pod is not yet started, the logs request below will throw an exception
try:
log_data = ""
for container in containers:
container_log = self.core_api.read_namespaced_pod_log(k8s_pod_name, namespace="default", container=container)
container_log_lines = container_log.splitlines()
for line in container_log_lines:
log_data += f"{container}: {line}\n"
log_data = self.core_api.read_namespaced_pod_log(k8s_pod_name, namespace="default", container="test")
except client.exceptions.ApiException as e:
if opts.o.debug:
print(f"Error from read_namespaced_pod_log: {e}")
+24 -105
View File
@@ -13,14 +13,12 @@
# 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/>.
from kubernetes import client, utils, watch
from kubernetes import client
import os
from pathlib import Path
import subprocess
import re
from typing import Set, Mapping, List
from stack_orchestrator.util import get_k8s_dir, error_exit
from stack_orchestrator.opts import opts
from stack_orchestrator.deploy.deploy_util import parsed_pod_files_map_from_file_names
from stack_orchestrator.deploy.deployer import DeployerException
@@ -45,33 +43,6 @@ def destroy_cluster(name: str):
_run_command(f"kind delete cluster --name {name}")
def wait_for_ingress_in_kind():
core_v1 = client.CoreV1Api()
for i in range(20):
warned_waiting = False
w = watch.Watch()
for event in w.stream(func=core_v1.list_namespaced_pod,
namespace="ingress-nginx",
label_selector="app.kubernetes.io/component=controller",
timeout_seconds=30):
if event['object'].status.container_statuses:
if event['object'].status.container_statuses[0].ready is True:
if warned_waiting:
print("Ingress controller is ready")
return
print("Waiting for ingress controller to become ready...")
warned_waiting = True
error_exit("ERROR: Timed out waiting for ingress to become ready")
def install_ingress_for_kind():
api_client = client.ApiClient()
ingress_install = os.path.abspath(get_k8s_dir().joinpath("components", "ingress", "ingress-nginx-kind-deploy.yaml"))
if opts.o.debug:
print("Installing nginx ingress controller in kind cluster")
utils.create_from_yaml(api_client, yaml_file=ingress_install)
def load_images_into_kind(kind_cluster_name: str, image_set: Set[str]):
for image in image_set:
result = _run_command(f"kind load docker-image {image} --name {kind_cluster_name}")
@@ -90,17 +61,6 @@ def pods_in_deployment(core_api: client.CoreV1Api, deployment_name: str):
return pods
def containers_in_pod(core_api: client.CoreV1Api, pod_name: str):
containers = []
pod_response = core_api.read_namespaced_pod(pod_name, namespace="default")
if opts.o.debug:
print(f"pod_response: {pod_response}")
pod_containers = pod_response.spec.containers
for pod_container in pod_containers:
containers.append(pod_container.name)
return containers
def log_stream_from_string(s: str):
# Note response has to be UTF-8 encoded because the caller expects to decode it
yield ("ignore", s.encode())
@@ -120,7 +80,7 @@ def named_volumes_from_pod_files(parsed_pod_files):
return named_volumes
def get_kind_pv_bind_mount_path(volume_name: str):
def get_node_pv_mount_path(volume_name: str):
return f"/mnt/{volume_name}"
@@ -145,14 +105,11 @@ def volume_mounts_for_service(parsed_pod_files, service):
mount_path = mount_split[1]
mount_options = mount_split[2] if len(mount_split) == 3 else None
if opts.o.debug:
print(f"volume_name: {volume_name}")
print(f"volumne_name: {volume_name}")
print(f"mount path: {mount_path}")
print(f"mount options: {mount_options}")
volume_device = client.V1VolumeMount(
mount_path=mount_path,
name=volume_name,
read_only="ro" == mount_options
)
mount_path=mount_path, name=volume_name, read_only="ro" == mount_options)
result.append(volume_device)
return result
@@ -175,8 +132,18 @@ def volumes_for_pod_files(parsed_pod_files, spec, app_name):
return result
def _get_host_paths_for_volumes(deployment_context):
return deployment_context.spec.get_volumes()
def _get_host_paths_for_volumes(parsed_pod_files):
result = {}
for pod in parsed_pod_files:
parsed_pod_file = parsed_pod_files[pod]
if "volumes" in parsed_pod_file:
volumes = parsed_pod_file["volumes"]
for volume_name in volumes.keys():
volume_definition = volumes[volume_name]
if volume_definition and "driver_opts" in volume_definition:
host_path = volume_definition["driver_opts"]["device"]
result[volume_name] = host_path
return result
def _make_absolute_host_path(data_mount_path: Path, deployment_dir: Path) -> Path:
@@ -184,12 +151,12 @@ def _make_absolute_host_path(data_mount_path: Path, deployment_dir: Path) -> Pat
return data_mount_path
else:
# Python Path voodo that looks pretty odd:
return Path.cwd().joinpath(deployment_dir.joinpath(data_mount_path)).resolve()
return Path.cwd().joinpath(deployment_dir.joinpath("compose").joinpath(data_mount_path)).resolve()
def _generate_kind_mounts(parsed_pod_files, deployment_dir, deployment_context):
volume_definitions = []
volume_host_path_map = _get_host_paths_for_volumes(deployment_context)
volume_host_path_map = _get_host_paths_for_volumes(parsed_pod_files)
# Note these paths are relative to the location of the pod files (at present)
# So we need to fix up to make them correct and absolute because kind assumes
# relative to the cwd.
@@ -209,15 +176,14 @@ def _generate_kind_mounts(parsed_pod_files, deployment_dir, deployment_context):
volume_name = mount_split[0]
mount_path = mount_split[1]
if opts.o.debug:
print(f"volume_name: {volume_name}")
print(f"volumne_name: {volume_name}")
print(f"map: {volume_host_path_map}")
print(f"mount path: {mount_path}")
if volume_name not in deployment_context.spec.get_configmaps():
if volume_host_path_map[volume_name]:
volume_definitions.append(
f" - hostPath: {_make_absolute_host_path(volume_host_path_map[volume_name], deployment_dir)}\n"
f" containerPath: {get_kind_pv_bind_mount_path(volume_name)}\n"
)
volume_definitions.append(
f" - hostPath: {_make_absolute_host_path(volume_host_path_map[volume_name], deployment_dir)}\n"
f" containerPath: {get_node_pv_mount_path(volume_name)}\n"
)
return (
"" if len(volume_definitions) == 0 else (
" extraMounts:\n"
@@ -226,8 +192,7 @@ def _generate_kind_mounts(parsed_pod_files, deployment_dir, deployment_context):
)
# TODO: decide if we need this functionality
def _generate_kind_port_mappings_from_services(parsed_pod_files):
def _generate_kind_port_mappings(parsed_pod_files):
port_definitions = []
for pod in parsed_pod_files:
parsed_pod_file = parsed_pod_files[pod]
@@ -249,46 +214,6 @@ def _generate_kind_port_mappings_from_services(parsed_pod_files):
)
def _generate_kind_port_mappings(parsed_pod_files):
port_definitions = []
# For now we just map port 80 for the nginx ingress controller we install in kind
port_string = "80"
port_definitions.append(f" - containerPort: {port_string}\n hostPort: {port_string}\n")
return (
"" if len(port_definitions) == 0 else (
" extraPortMappings:\n"
f"{''.join(port_definitions)}"
)
)
# Note: this makes any duplicate definition in b overwrite a
def merge_envs(a: Mapping[str, str], b: Mapping[str, str]) -> Mapping[str, str]:
result = {**a, **b}
return result
def _expand_shell_vars(raw_val: str) -> str:
# could be: <string> or ${<env-var-name>} or ${<env-var-name>:-<default-value>}
# TODO: implement support for variable substitution and default values
# if raw_val is like ${<something>} print a warning and substitute an empty string
# otherwise return raw_val
match = re.search(r"^\$\{(.*)\}$", raw_val)
if match:
print(f"WARNING: found unimplemented environment variable substitution: {raw_val}")
else:
return raw_val
# TODO: handle the case where the same env var is defined in multiple places
def envs_from_compose_file(compose_file_envs: Mapping[str, str]) -> Mapping[str, str]:
result = {}
for env_var, env_val in compose_file_envs.items():
expanded_env_val = _expand_shell_vars(env_val)
result.update({env_var: expanded_env_val})
return result
def envs_from_environment_variables_map(map: Mapping[str, str]) -> List[client.V1EnvVar]:
result = []
for env_var, env_val in map.items():
@@ -326,12 +251,6 @@ def generate_kind_config(deployment_dir: Path, deployment_context):
"apiVersion: kind.x-k8s.io/v1alpha4\n"
"nodes:\n"
"- role: control-plane\n"
" kubeadmConfigPatches:\n"
" - |\n"
" kind: InitConfiguration\n"
" nodeRegistration:\n"
" kubeletExtraArgs:\n"
" node-labels: \"ingress-ready=true\"\n"
f"{port_mappings_yml}\n"
f"{mounts_yml}\n"
)
+5 -93
View File
@@ -13,77 +13,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 typing
import humanfriendly
from pathlib import Path
import typing
from stack_orchestrator.util import get_yaml
from stack_orchestrator import constants
class ResourceLimits:
cpus: float = None
memory: int = None
storage: int = None
def __init__(self, obj={}):
if "cpus" in obj:
self.cpus = float(obj["cpus"])
if "memory" in obj:
self.memory = humanfriendly.parse_size(obj["memory"])
if "storage" in obj:
self.storage = humanfriendly.parse_size(obj["storage"])
def __len__(self):
return len(self.__dict__)
def __iter__(self):
for k in self.__dict__:
yield k, self.__dict__[k]
def __repr__(self):
return str(self.__dict__)
class Resources:
limits: ResourceLimits = None
reservations: ResourceLimits = None
def __init__(self, obj={}):
if "reservations" in obj:
self.reservations = ResourceLimits(obj["reservations"])
if "limits" in obj:
self.limits = ResourceLimits(obj["limits"])
def __len__(self):
return len(self.__dict__)
def __iter__(self):
for k in self.__dict__:
yield k, self.__dict__[k]
def __repr__(self):
return str(self.__dict__)
class Spec:
obj: typing.Any
file_path: Path
def __init__(self, file_path: Path = None, obj={}) -> None:
self.file_path = file_path
self.obj = obj
def __getitem__(self, item):
return self.obj[item]
def __contains__(self, item):
return item in self.obj
def get(self, item, default=None):
return self.obj.get(item, default)
def __init__(self) -> None:
pass
def init_from_file(self, file_path: Path):
with file_path:
@@ -91,8 +33,8 @@ class Spec:
self.file_path = file_path
def get_image_registry(self):
return (self.obj[constants.image_registry_key]
if self.obj and constants.image_registry_key in self.obj
return (self.obj[constants.image_resigtry_key]
if self.obj and constants.image_resigtry_key in self.obj
else None)
def get_volumes(self):
@@ -105,38 +47,8 @@ class Spec:
if self.obj and "configmaps" in self.obj
else {})
def get_container_resources(self):
return Resources(self.obj.get("resources", {}).get("containers", {}))
def get_volume_resources(self):
return Resources(self.obj.get("resources", {}).get("volumes", {}))
def get_http_proxy(self):
return (self.obj[constants.network_key][constants.http_proxy_key]
if self.obj and constants.network_key in self.obj
and constants.http_proxy_key in self.obj[constants.network_key]
else None)
def get_annotations(self):
return self.obj.get("annotations", {})
def get_labels(self):
return self.obj.get("labels", {})
def get_privileged(self):
return "true" == str(self.obj.get("security", {}).get("privileged", "false")).lower()
def get_capabilities(self):
return self.obj.get("security", {}).get("capabilities", [])
def get_deployment_type(self):
return self.obj[constants.deploy_to_key]
def is_kubernetes_deployment(self):
return self.get_deployment_type() in [constants.k8s_kind_deploy_type, constants.k8s_deploy_type]
def is_kind_deployment(self):
return self.get_deployment_type() in [constants.k8s_kind_deploy_type]
def is_docker_deployment(self):
return self.get_deployment_type() in [constants.compose_deploy_type]
@@ -44,7 +44,7 @@ def _fixup_url_spec(spec_file_name: str, url: str):
- host-name: {parsed_url.hostname}
routes:
- path: '{parsed_url.path if parsed_url.path else "/"}'
proxy-to: webapp:80
proxy-to: webapp:3000
'''
spec_file_path = Path(spec_file_name)
with open(spec_file_path) as rfile:
@@ -19,8 +19,6 @@ import shlex
import shutil
import sys
import tempfile
import time
import uuid
import click
@@ -29,7 +27,7 @@ from stack_orchestrator.deploy.webapp.util import (LaconicRegistryClient,
build_container_image, push_container_image,
file_hash, deploy_to_k8s, publish_deployment,
hostname_for_deployment_request, generate_hostname_for_app,
match_owner, skip_by_tag)
match_owner)
def process_app_deployment_request(
@@ -41,19 +39,8 @@ def process_app_deployment_request(
dns_suffix,
deployment_parent_dir,
kube_config,
image_registry,
log_parent_dir
image_registry
):
run_id = f"{app_deployment_request.id}-{str(time.time()).split('.')[0]}-{str(uuid.uuid4()).split('-')[0]}"
log_file = None
if log_parent_dir:
log_dir = os.path.join(log_parent_dir, app_deployment_request.id)
if not os.path.exists(log_dir):
os.mkdir(log_dir)
log_file_path = os.path.join(log_dir, f"{run_id}.log")
print(f"Directing build logs to: {log_file_path}")
log_file = open(log_file_path, "wt")
# 1. look up application
app = laconic.get_record(app_deployment_request.attributes.application, require=True)
@@ -115,10 +102,8 @@ def process_app_deployment_request(
needs_k8s_deploy = False
# 6. build container (if needed)
if not deployment_record or deployment_record.attributes.application != app.id:
# TODO: pull from request
extra_build_args = []
build_container_image(app, deployment_container_tag, extra_build_args, log_file)
push_container_image(deployment_dir, log_file)
build_container_image(app, deployment_container_tag)
push_container_image(deployment_dir)
needs_k8s_deploy = True
# 7. update config (if needed)
@@ -131,7 +116,6 @@ def process_app_deployment_request(
deploy_to_k8s(
deployment_record,
deployment_dir,
log_file
)
publish_deployment(
@@ -178,14 +162,10 @@ def dump_known_requests(filename, requests, status="SEEN"):
@click.option("--record-namespace-dns", help="eg, crn://laconic/dns")
@click.option("--record-namespace-deployments", help="eg, crn://laconic/deployments")
@click.option("--dry-run", help="Don't do anything, just report what would be done.", is_flag=True)
@click.option("--include-tags", help="Only include requests with matching tags (comma-separated).", default="")
@click.option("--exclude-tags", help="Exclude requests with matching tags (comma-separated).", default="")
@click.option("--log-dir", help="Output build/deployment logs to directory.", default=None)
@click.pass_context
def command(ctx, kube_config, laconic_config, image_registry, deployment_parent_dir, # noqa: C901
def command(ctx, kube_config, laconic_config, image_registry, deployment_parent_dir,
request_id, discover, state_file, only_update_state,
dns_suffix, record_namespace_dns, record_namespace_deployments, dry_run,
include_tags, exclude_tags, log_dir):
dns_suffix, record_namespace_dns, record_namespace_deployments, dry_run):
if request_id and discover:
print("Cannot specify both --request-id and --discover", file=sys.stderr)
sys.exit(2)
@@ -203,10 +183,6 @@ def command(ctx, kube_config, laconic_config, image_registry, deployment_parent_
print("--dns-suffix, --record-namespace-dns, and --record-namespace-deployments are all required", file=sys.stderr)
sys.exit(2)
# Split CSV and clean up values.
include_tags = [tag.strip() for tag in include_tags.split(",") if tag]
exclude_tags = [tag.strip() for tag in exclude_tags.split(",") if tag]
laconic = LaconicRegistryClient(laconic_config)
# Find deployment requests.
@@ -228,7 +204,6 @@ def command(ctx, kube_config, laconic_config, image_registry, deployment_parent_
requests.sort(key=lambda r: r.createTime)
requests.reverse()
requests_by_name = {}
skipped_by_name = {}
for r in requests:
# TODO: Do this _after_ filtering deployments and cancellations to minimize round trips.
app = laconic.get_record(r.attributes.application)
@@ -241,20 +216,17 @@ def command(ctx, kube_config, laconic_config, image_registry, deployment_parent_
requested_name = generate_hostname_for_app(app)
print("Generating name %s for request %s." % (requested_name, r.id))
if requested_name in skipped_by_name or requested_name in requests_by_name:
print("Ignoring request %s, it has been superseded." % r.id)
continue
if skip_by_tag(r, include_tags, exclude_tags):
print("Skipping request %s, filtered by tag (include %s, exclude %s, present %s)" % (r.id,
include_tags,
exclude_tags,
r.attributes.tags))
skipped_by_name[requested_name] = r
continue
print("Found request %s to run application %s on %s." % (r.id, r.attributes.application, requested_name))
requests_by_name[requested_name] = r
if requested_name not in requests_by_name:
print(
"Found request %s to run application %s on %s."
% (r.id, r.attributes.application, requested_name)
)
requests_by_name[requested_name] = r
else:
print(
"Ignoring request %s, it is superseded by %s."
% (r.id, requests_by_name[requested_name].id)
)
# Find deployments.
deployments = laconic.app_deployments()
@@ -301,8 +273,7 @@ def command(ctx, kube_config, laconic_config, image_registry, deployment_parent_
dns_suffix,
os.path.abspath(deployment_parent_dir),
kube_config,
image_registry,
log_dir
image_registry
)
status = "DEPLOYED"
finally:
@@ -20,7 +20,7 @@ import sys
import click
from stack_orchestrator.deploy.webapp.util import LaconicRegistryClient, match_owner, skip_by_tag
from stack_orchestrator.deploy.webapp.util import LaconicRegistryClient, match_owner
def process_app_removal_request(ctx,
@@ -107,12 +107,10 @@ def dump_known_requests(filename, requests):
@click.option("--delete-names/--preserve-names", help="Delete all names associated with removed deployments.", default=True)
@click.option("--delete-volumes/--preserve-volumes", default=True, help="delete data volumes")
@click.option("--dry-run", help="Don't do anything, just report what would be done.", is_flag=True)
@click.option("--include-tags", help="Only include requests with matching tags (comma-separated).", default="")
@click.option("--exclude-tags", help="Exclude requests with matching tags (comma-separated).", default="")
@click.pass_context
def command(ctx, laconic_config, deployment_parent_dir,
request_id, discover, state_file, only_update_state,
delete_names, delete_volumes, dry_run, include_tags, exclude_tags):
delete_names, delete_volumes, dry_run):
if request_id and discover:
print("Cannot specify both --request-id and --discover", file=sys.stderr)
sys.exit(2)
@@ -125,10 +123,6 @@ def command(ctx, laconic_config, deployment_parent_dir,
print("--only-update-state requires --state-file", file=sys.stderr)
sys.exit(2)
# Split CSV and clean up values.
include_tags = [tag.strip() for tag in include_tags.split(",") if tag]
exclude_tags = [tag.strip() for tag in exclude_tags.split(",") if tag]
laconic = LaconicRegistryClient(laconic_config)
# Find deployment removal requests.
@@ -147,7 +141,6 @@ def command(ctx, laconic_config, deployment_parent_dir,
previous_requests = load_known_requests(state_file)
requests.sort(key=lambda r: r.createTime)
requests.reverse()
# Find deployments.
deployments = {}
@@ -162,22 +155,10 @@ def command(ctx, laconic_config, deployment_parent_dir,
# TODO: should we handle CRNs?
removals_by_deployment[r.attributes.deployment] = r
one_per_deployment = {}
requests_to_execute = []
for r in requests:
if not r.attributes.deployment:
print(f"Skipping removal request {r.id} since it was a cancellation.")
elif r.attributes.deployment in one_per_deployment:
print(f"Skipping removal request {r.id} since it was superseded.")
else:
one_per_deployment[r.attributes.deployment] = r
requests_to_execute = []
for r in one_per_deployment.values():
if skip_by_tag(r, include_tags, exclude_tags):
print("Skipping removal request %s, filtered by tag (include %s, exclude %s, present %s)" % (r.id,
include_tags,
exclude_tags,
r.attributes.tags))
elif r.id in removals_by_request:
print(f"Found satisfied request for {r.id} at {removals_by_request[r.id].id}")
elif r.attributes.deployment in removals_by_deployment:
+9 -25
View File
@@ -212,7 +212,7 @@ def determine_base_container(clone_dir, app_type="webapp"):
return base_container
def build_container_image(app_record, tag, extra_build_args=[], log_file=None):
def build_container_image(app_record, tag, extra_build_args=[]):
tmpdir = tempfile.mkdtemp()
try:
@@ -227,10 +227,10 @@ def build_container_image(app_record, tag, extra_build_args=[], log_file=None):
git_env = dict(os.environ.copy())
# Never prompt
git_env["GIT_TERMINAL_PROMPT"] = "0"
subprocess.check_call(["git", "clone", repo, clone_dir], env=git_env, stdout=log_file, stderr=log_file)
subprocess.check_call(["git", "checkout", ref], cwd=clone_dir, env=git_env, stdout=log_file, stderr=log_file)
subprocess.check_call(["git", "clone", repo, clone_dir], env=git_env)
subprocess.check_call(["git", "checkout", ref], cwd=clone_dir, env=git_env)
else:
result = subprocess.run(["git", "clone", "--depth", "1", repo, clone_dir], stdout=log_file, stderr=log_file)
result = subprocess.run(["git", "clone", "--depth", "1", repo, clone_dir])
result.check_returncode()
base_container = determine_base_container(clone_dir, app_record.attributes.app_type)
@@ -246,27 +246,25 @@ def build_container_image(app_record, tag, extra_build_args=[], log_file=None):
build_command.append("--extra-build-args")
build_command.append(" ".join(extra_build_args))
result = subprocess.run(build_command, stdout=log_file, stderr=log_file)
result = subprocess.run(build_command)
result.check_returncode()
finally:
cmd("rm", "-rf", tmpdir)
def push_container_image(deployment_dir, log_file=None):
def push_container_image(deployment_dir):
print("Pushing image ...")
result = subprocess.run([sys.argv[0], "deployment", "--dir", deployment_dir, "push-images"],
stdout=log_file, stderr=log_file)
result = subprocess.run([sys.argv[0], "deployment", "--dir", deployment_dir, "push-images"])
result.check_returncode()
def deploy_to_k8s(deploy_record, deployment_dir, log_file=None):
def deploy_to_k8s(deploy_record, deployment_dir):
if not deploy_record:
command = "up"
else:
command = "update"
result = subprocess.run([sys.argv[0], "deployment", "--dir", deployment_dir, command],
stdout=log_file, stderr=log_file)
result = subprocess.run([sys.argv[0], "deployment", "--dir", deployment_dir, command])
result.check_returncode()
@@ -351,17 +349,3 @@ def generate_hostname_for_app(app):
else:
m.update(app.attributes.repository.encode())
return "%s-%s" % (last_part, m.hexdigest()[0:10])
def skip_by_tag(r, include_tags, exclude_tags):
for tag in exclude_tags:
if r.attributes.tags and tag in r.attributes.tags:
return True
if include_tags:
for tag in include_tags:
if r.attributes.tags and tag in r.attributes.tags:
return False
return True
return False

Some files were not shown because too many files have changed in this diff Show More