Compare commits

...
Author SHA1 Message Date
dboreham c6df9ae0c1 Merge pull request #131 from cerc-io/dboreham/stack-for-npm-build
Stack for build-npms

Former-commit-id: 683341a66f
2023-01-18 22:02:49 -07:00
dboreham f1cd13d988 Stack for build-npms
Former-commit-id: 0b8b3123fe
2023-01-18 22:01:55 -07:00
dboreham edc24e4fc8 Merge pull request #130 from cerc-io/dboreham/stack-for-deploy-system
Implement stack for deploy-system

Former-commit-id: 7740dccf4c
2023-01-18 15:37:41 -07:00
dboreham 533ed4ee9b Implement stack for deploy-system
Former-commit-id: 6bf413e002
2023-01-18 15:37:12 -07:00
dboreham ba5eecaada Merge pull request #129 from cerc-io/dboreham/stack-for-build-containers
Implement stack for container build

Former-commit-id: d1f9c3d152
2023-01-18 15:28:53 -07:00
dboreham 5f73a93f5f Implement stack for container build
Former-commit-id: d5875954b8
2023-01-18 15:27:52 -07:00
dboreham 135295f0f9 Update version
Former-commit-id: 5e2df891cf
2023-01-17 22:43:07 -07:00
dboreham 5b4f935afd Merge pull request #128 from cerc-io/dboreham/stack-for-setup-repositories
Implement stack config file for setup-repositories

Former-commit-id: 4e1366df60
2023-01-17 22:40:12 -07:00
dboreham 5a4220ff41 Update version info
Former-commit-id: b0947081de
2023-01-17 22:38:30 -07:00
dboreham a60fb08c8a Make code compatible with Pyton 3.8
Former-commit-id: 04a3049162
2023-01-17 22:25:04 -07:00
dboreham 2b15eff104 Initial implementation of stack
Former-commit-id: 1d7128c6e1
2023-01-17 16:05:50 -07:00
dboreham fc3bcdef74 Merge pull request #127 from cerc-io/dboreham/update-version
Update version

Former-commit-id: 65f5382bfe
2023-01-17 13:52:33 -07:00
dboreham 500c481d6b Update version
Former-commit-id: cf3120d6c2
2023-01-17 13:52:00 -07:00
telackey 08d5c22f32 Enable metrics endpoint in fixturenet.
Former-commit-id: 0ea29bc480
2023-01-17 12:04:28 -06:00
Zach 8fb71711bc Merge pull request #122 from cerc-io/update-readme-67
Update readme

Former-commit-id: 5e7db36c75
2023-01-17 09:27:42 -05:00
dboreham 32b4c00261 Merge pull request #124 from cerc-io/dboreham/fix-fixturenet-geth-build
Fix fixturenet container builds in shiv mode
2023-01-16 21:58:03 -07:00
dboreham 71425b93f6 Package deep enough into the data tree to get all the files that are there 2023-01-16 21:56:07 -07:00
zramsay b90e4ad6cd update readme
Former-commit-id: 70723dd6d4
2023-01-16 07:27:52 -05:00
telackey b13300ca81 Add CERC_STATEDIFF_DB_LOG_STATEMENTS=true|false option. (#120) 2023-01-13 16:33:59 -06:00
telackey 6396de1ecf Improvements for building/deploying geth. (#119)
* Improvements for building/deploying geth.

* Improvements for building/deploying geth.
2023-01-12 11:37:23 -06:00
dboreham 18a7e59a8a Merge pull request #116 from cerc-io/dboreham/fix-imports
Fix imports
2023-01-11 21:57:26 -07:00
David Boreham 0a66b7e9d2 Fix odd import problem 2023-01-11 21:56:05 -07:00
David Boreham 7edfa1bb29 Add import-resources dependency 2023-01-11 21:01:48 -07:00
telackey 8e184f509d Add remote debugging support to fixturenet-geth. (#113)
* Add remote debugging support to fixturenet-geth.
2023-01-11 12:54:22 -06:00
23 changed files with 447 additions and 337 deletions
+91
View File
@@ -0,0 +1,91 @@
# Contributing
Thank you for taking the time to make a contribution to Stack Orchestrator.
## Install (developer mode)
Suitable for developers either modifying or debugging the orchestrator Python code:
#### Prerequisites
In addition to the binary install prerequisites listed above, the following are required:
1. Python venv package
This may or may not be already installed depending on the host OS and version. Check by running:
```
$ python3 -m venv
usage: venv [-h] [--system-site-packages] [--symlinks | --copies] [--clear] [--upgrade] [--without-pip] [--prompt PROMPT] ENV_DIR [ENV_DIR ...]
venv: error: the following arguments are required: ENV_DIR
```
If the venv package is missing you should see a message indicating how to install it, for example with:
```
$ apt install python3.10-venv
```
#### Install
1. Clone this repository:
```
$ git clone (https://github.com/cerc-io/stack-orchestrator.git
```
4. Enter the project directory:
```
$ cd stack-orchestrator
```
5. Create and activate a venv:
```
$ python3 -m venv venv
$ source ./venv/bin/activate
(venv) $
```
6. Install the cli in edit mode:
```
$ pip install --editable .
```
7. Verify installation:
```
(venv) $ laconic-so
Usage: laconic-so [OPTIONS] COMMAND [ARGS]...
Laconic Stack Orchestrator
Options:
--quiet
--verbose
--dry-run
-h, --help Show this message and exit.
Commands:
build-containers build the set of containers required for a complete...
deploy-system deploy a stack
setup-repositories git clone the set of repositories required to build...
```
#### Build a zipapp (single file distributable script)
Use shiv to build a single file Python executable zip archive of laconic-so:
1. Install [shiv](https://github.com/linkedin/shiv):
```
$ (venv) pip install shiv
$ (venv) pip install wheel
```
1. Run shiv to create a zipapp file:
```
$ (venv) shiv -c laconic-so -o laconic-so .
```
This creates a file `./laconic-so` that is executable outside of any venv, and on other machines and OSes and architectures, and requiring only the system Python3:
1. Verify it works:
```
$ cp stack-orchetrator/laconic-so ~/bin
$ laconic-so
Usage: python -m laconic-so [OPTIONS] COMMAND [ARGS]...
Laconic Stack Orchestrator
Options:
--quiet
--verbose
--dry-run
-h, --help Show this message and exit.
Commands:
build-containers build the set of containers required for a complete...
deploy-system deploy a stack
setup-repositories git clone the set of repositories required to build...
```
+72 -185
View File
@@ -1,218 +1,105 @@
# Stack Orchestrator # Stack Orchestrator
Stack Orchestrator allows building and deployment of a Laconic stack on a single machine with minimial prerequisites. Stack Orchestrator allows building and deployment of a Laconic Stack on a single machine with minimial prerequisites. It is a Python3 CLI tool that runs on any OS with Python3 and Docker. The following diagram summarizes the relevant repositories in the Laconic Stack - and the relationship to Stack Orchestrator.
## Setup ![The Stack](/docs/images/laconic-stack.png)
### Prerequisites
Stack Orchestrator is a Python3 CLI tool that runs on any OS with Python3 and Docker. Tested on: Ubuntu 20/22. ## Install
Ensure that the following are already installed: Ensure that the following are already installed:
1. Python3 (the stock Python3 version available in Ubuntu 20 and 22 is suitable) - [Python3](https://wiki.python.org/moin/BeginnersGuide/Download)
``` - [Docker](https://docs.docker.com/get-docker/)
$ python3 --version - [Docker Compose](https://docs.docker.com/compose/install/)
Python 3.8.10
```
2. Docker (Install a current version from dockerco, don't use the version from any Linux distro)
```
$ docker --version
Docker version 20.10.17, build 100c701
```
3. If installed from regular package repository (not Docker Desktop), BE AWARE that the compose plugin may need to be installed, as well.
```
DOCKER_CONFIG=${DOCKER_CONFIG:-$HOME/.docker}
mkdir -p $DOCKER_CONFIG/cli-plugins
curl -SL https://github.com/docker/compose/releases/download/v2.11.2/docker-compose-linux-x86_64 -o $DOCKER_CONFIG/cli-plugins/docker-compose
chmod +x ~/.docker/cli-plugins/docker-compose
# see https://docs.docker.com/compose/install/linux/#install-the-plugin-manually for further details Note: if installing docker-compose via package manager (as opposed to Docker Desktop), you must [install the plugin](https://docs.docker.com/compose/install/linux/#install-the-plugin-manually), e.g., on Linux:
# or to install for all users.
```
### User Mode Install ```bash
mkdir -p ~/.docker/cli-plugins
curl -SL https://github.com/docker/compose/releases/download/v2.11.2/docker-compose-linux-x86_64 -o ~/.docker/cli-plugins/docker-compose
chmod +x ~/.docker/cli-plugins/docker-compose
```
User mode runs the orchestrator from a "binary" single-file release and does not require special Python environment setup. Use this mode unless you plan to make changes to the orchestrator source code. Next, download the latest release from [this page](https://github.com/cerc-io/stack-orchestrator/tags), into a suitable directory (e.g. `~/bin`):
*NOTE: User Mode is currently broken, use "Developer mode" described below for now.* ```bash
curl -L -o ~/bin/laconic-so https://github.com/cerc-io/stack-orchestrator/releases/latest/download/laconic-so
```
1. Download the latest release from [this page](https://github.com/cerc-io/stack-orchestrator/tags), into a suitable directory (e.g. `~/bin`): Give it permissions:
``` ```bash
$ cd ~/bin chmod +x ~/bin/laconic-so
$ curl -L https://github.com/cerc-io/stack-orchestrator/releases/download/v1.0.3-alpha/laconic-so ```
```
1. Ensure `laconic-so` is on the `PATH`
1. Verify operation:
```
$ ~/bin/laconic-so --help
Usage: python -m laconic-so [OPTIONS] COMMAND [ARGS]...
Laconic Stack Orchestrator Ensure `laconic-so` is on the [`PATH`](https://unix.stackexchange.com/a/26059)
Options: Verify operation:
--quiet
--verbose
--dry-run
--local-stack
-h, --help Show this message and exit.
Commands: ```
build-containers build the set of containers required for a complete... laconic-so --help
deploy-system deploy a stack Usage: python -m laconic-so [OPTIONS] COMMAND [ARGS]...
setup-repositories git clone the set of repositories required to build...
```
### Developer mode Install
Suitable for developers either modifying or debugging the orchestrator Python code:
#### Prerequisites
In addition to the binary install prerequisites listed above, the following are required:
1. Python venv package
This may or may not be already installed depending on the host OS and version. Check by running:
```
$ python3 -m venv
usage: venv [-h] [--system-site-packages] [--symlinks | --copies] [--clear] [--upgrade] [--without-pip] [--prompt PROMPT] ENV_DIR [ENV_DIR ...]
venv: error: the following arguments are required: ENV_DIR
```
If the venv package is missing you should see a message indicating how to install it, for example with:
```
$ apt install python3.8-venv
```
#### Install
1. Clone this repository:
```
$ git clone (https://github.com/cerc-io/stack-orchestrator.git
```
4. Enter the project directory:
```
$ cd stack-orchestrator
```
5. Create and activate a venv:
```
$ python3 -m venv venv
$ source ./venv/bin/activate
(venv) $
```
6. Install the cli in edit mode:
```
$ pip install --editable .
```
7. Verify installation:
```
(venv) $ laconic-so
Usage: laconic-so [OPTIONS] COMMAND [ARGS]...
Laconic Stack Orchestrator Laconic Stack Orchestrator
Options: Options:
--quiet --quiet
--verbose --verbose
--dry-run --dry-run
-h, --help Show this message and exit. --local-stack
-h, --help Show this message and exit.
Commands: Commands:
build-containers build the set of containers required for a complete... build-containers build the set of containers required for a complete...
deploy-system deploy a stack build-npms build the set of npm packages required for a...
setup-repositories git clone the set of repositories required to build... deploy-system deploy a stack
``` setup-repositories git clone the set of repositories required to build...
```
#### Build a zipapp (single file distributable script)
Use shiv to build a single file Python executable zip archive of laconic-so:
1. Install [shiv](https://github.com/linkedin/shiv):
```
$ (venv) pip install shiv
$ (venv) pip install wheel
```
1. Run shiv to create a zipapp file:
```
$ (venv) shiv -c laconic-so -o laconic-so .
```
This creates a file `./laconic-so` that is executable outside of any venv, and on other machines and OSes and architectures, and requiring only the system Python3:
1. Verify it works:
```
$ cp stack-orchetrator/laconic-so ~/bin
$ laconic-so
Usage: python -m laconic-so [OPTIONS] COMMAND [ARGS]...
Laconic Stack Orchestrator
Options:
--quiet
--verbose
--dry-run
-h, --help Show this message and exit.
Commands:
build-containers build the set of containers required for a complete...
deploy-system deploy a stack
setup-repositories git clone the set of repositories required to build...
```
### CI Mode
_write-me_
## Usage ## Usage
There are three sub-commands: `setup-repositories`, `build-containers` and `deploy-system` that are generally run in order:
Note: $ laconic-so will run the version installed to ~/bin, while ./laconic-so can be invoked to run locally built Three sub-commands: `setup-repositories`, `build-containers` and `deploy-system` are generally run in order. The following is a slim example for standing up the `erc20-watcher`. Go further with the [erc20 watcher demo](/app/data/stacks/erc20) and other pieces of the stack, within the [`stacks` directory](/app/data/stacks).
version in a checkout
### Setup Repositories ### Setup Repositories
Clones the set of git repositories necessary to build a system.
Note: the use of `ssh-agent` is recommended in order to avoid entering your ssh key passphrase for each repository. Clone the set of git repositories necessary to build a system:
```
$ laconic-so --verbose setup-repositories #this will default to ~/cerc or CERC_REPO_BASE_DIR from an env file ```bash
#$ ./laconic-so --verbose --local-stack setup-repositories #this will use cwd ../ as dev_root_path laconic-so --verbose setup-repositories --include cerc-io/go-ethereum,cerc-io/ipld-eth-db,cerc-io/ipld-eth-server,cerc-io/watcher-ts
``` ```
This will default to `~/cerc` or - if set - the environment variable `CERC_REPO_BASE_DIR`
### Build Containers ### Build Containers
Builds the set of docker container images required to run a system. It takes around 10 minutes to build all the containers from cold.
```
$ laconic-so --verbose build-containers #this will default to ~/cerc or CERC_REPO_BASE_DIR from an env file
#$ ./laconic-so --verbose --local-stack build-containers #this will use cwd ../ as dev_root_path
Build the set of docker container images required to run a system. It takes around 10 minutes to build all the containers from scratch.
```bash
laconic-so --verbose build-containers --include cerc/go-ethereum,cerc/go-ethereum-foundry,cerc/ipld-eth-db,cerc/ipld-eth-server,cerc/watcher-erc20
``` ```
### Deploy System ### Deploy System
Uses `docker compose` to deploy a system.
Use `---include <list of components>` to deploy a subset of all containers: Uses `docker-compose` to deploy a system (with most recently built container images).
```bash
laconic-so --verbose deploy-system --include ipld-eth-db,go-ethereum-foundry,ipld-eth-server,watcher-erc20 up
``` ```
$ laconic-so --verbose deploy-system --include db-sharding,contract,ipld-eth-server,go-ethereum-foundry up
Check out he GraphQL playground here: [http://localhost:3002/graphql](http://localhost:3002/graphql)
See the [erc20 watcher demo](/app/data/stacks/erc20) to continue further.
### Cleanup
```bash
laconic-so --verbose deploy-system --include ipld-eth-db,go-ethereum-foundry,ipld-eth-server,watcher-erc20 down
``` ```
```
$ laconic-so --verbose deploy-system --include db-sharding,contract,ipld-eth-server,go-ethereum-foundry down ## Contributing
```
Note: deploy-system command interacts with most recently built container images. See the [CONTRIBUTING.md](.github/CONTRIBUTING.md) for developer mode install.
## Platform Support ## Platform Support
Native aarm64 is _not_ currently supported. x64 emulation on ARM64 macos should work (not yet tested).
## Implementation
The orchestrator's operation is driven by files shown below. `repository-list.txt` container the list of git repositories; `container-image-list.txt` contains
the list of container image names, while `clister-list.txt` specifies the set of compose components (corresponding to individual docker-compose-xxx.yml files which may in turn specify more than one container).
Files required to build each container image are stored under `./container-build/<container-name>`
Files required at deploy-time are stored under `./config/<component-name>`
```
├── pod-list.txt
├── compose
│   ├── docker-compose-contract.yml
│   ├── docker-compose-db-sharding.yml
│   ├── docker-compose-db.yml
│   ├── docker-compose-eth-statediff-fill-service.yml
│   ├── docker-compose-go-ethereum-foundry.yml
│   ├── docker-compose-ipld-eth-beacon-db.yml
│   ├── docker-compose-ipld-eth-beacon-indexer.yml
│   ├── docker-compose-ipld-eth-server.yml
│   ├── docker-compose-lighthouse.yml
│   └── docker-compose-prometheus-grafana.yml
├── config
│   └── ipld-eth-server
├── container-build
│   ├── cerc-eth-statediff-fill-service
│   ├── cerc-go-ethereum
│   ├── cerc-go-ethereum-foundry
│   ├── cerc-ipld-eth-beacon-db
│   ├── cerc-ipld-eth-beacon-indexer
│   ├── cerc-ipld-eth-db
│   ├── cerc-ipld-eth-server
│   ├── cerc-lighthouse
│   └── cerc-test-contract
├── container-image-list.txt
├── repository-list.txt
```
_write-more-of-me_ Native aarm64 is _not_ currently supported. x64 emulation on ARM64 macos should work (not yet tested).
+20 -4
View File
@@ -24,8 +24,9 @@ import os
from decouple import config from decouple import config
import subprocess import subprocess
import click import click
import importlib import importlib.resources
from pathlib import Path from pathlib import Path
import yaml
from .util import include_exclude_check from .util import include_exclude_check
# TODO: find a place for this # TODO: find a place for this
@@ -43,6 +44,7 @@ def command(ctx, include, exclude):
verbose = ctx.obj.verbose verbose = ctx.obj.verbose
dry_run = ctx.obj.dry_run dry_run = ctx.obj.dry_run
local_stack = ctx.obj.local_stack local_stack = ctx.obj.local_stack
stack = ctx.obj.stack
# See: https://stackoverflow.com/questions/25389095/python-get-path-of-root-project-structure # See: https://stackoverflow.com/questions/25389095/python-get-path-of-root-project-structure
container_build_dir = Path(__file__).absolute().parent.joinpath("data", "container-build") container_build_dir = Path(__file__).absolute().parent.joinpath("data", "container-build")
@@ -62,10 +64,24 @@ def command(ctx, include, exclude):
# See: https://stackoverflow.com/a/20885799/1701505 # See: https://stackoverflow.com/a/20885799/1701505
from . import data from . import data
with importlib.resources.open_text(data, "container-image-list.txt") as container_list_file: with importlib.resources.open_text(data, "container-image-list.txt") as container_list_file:
containers = container_list_file.read().splitlines() all_containers = container_list_file.read().splitlines()
containers_in_scope = []
if stack:
# In order to be compatible with Python 3.8 we need to use this hack to get the path:
# See: https://stackoverflow.com/questions/25389095/python-get-path-of-root-project-structure
stack_file_path = Path(__file__).absolute().parent.joinpath("data", "stacks", stack, "stack.yml")
with stack_file_path:
stack_config = yaml.safe_load(open(stack_file_path, "r"))
# TODO: syntax check the input here
containers_in_scope = stack_config['containers']
else:
containers_in_scope = all_containers
if verbose: if verbose:
print(f'Containers: {containers}') print(f'Containers: {containers_in_scope}')
if stack:
print(f"Stack: {stack}")
# TODO: make this configurable # TODO: make this configurable
container_build_env = { container_build_env = {
@@ -101,7 +117,7 @@ def command(ctx, include, exclude):
else: else:
print("Skipped") print("Skipped")
for container in containers: for container in containers_in_scope:
if include_exclude_check(container, include, exclude): if include_exclude_check(container, include, exclude):
process_container(container) process_container(container)
else: else:
+19 -4
View File
@@ -21,8 +21,10 @@
import os import os
from decouple import config from decouple import config
import click import click
import importlib import importlib.resources
from pathlib import Path
from python_on_whales import docker from python_on_whales import docker
import yaml
from .util import include_exclude_check from .util import include_exclude_check
@click.command() @click.command()
@@ -37,6 +39,7 @@ def command(ctx, include, exclude):
dry_run = ctx.obj.dry_run dry_run = ctx.obj.dry_run
local_stack = ctx.obj.local_stack local_stack = ctx.obj.local_stack
debug = ctx.obj.debug debug = ctx.obj.debug
stack = ctx.obj.stack
if local_stack: if local_stack:
dev_root_path = os.getcwd()[0:os.getcwd().rindex("stack-orchestrator")] dev_root_path = os.getcwd()[0:os.getcwd().rindex("stack-orchestrator")]
@@ -53,10 +56,22 @@ def command(ctx, include, exclude):
# See: https://stackoverflow.com/a/20885799/1701505 # See: https://stackoverflow.com/a/20885799/1701505
from . import data from . import data
with importlib.resources.open_text(data, "npm-package-list.txt") as package_list_file: with importlib.resources.open_text(data, "npm-package-list.txt") as package_list_file:
packages = package_list_file.read().splitlines() all_packages = package_list_file.read().splitlines()
packages_in_scope = []
if stack:
# In order to be compatible with Python 3.8 we need to use this hack to get the path:
# See: https://stackoverflow.com/questions/25389095/python-get-path-of-root-project-structure
stack_file_path = Path(__file__).absolute().parent.joinpath("data", "stacks", stack, "stack.yml")
with stack_file_path:
stack_config = yaml.safe_load(open(stack_file_path, "r"))
# TODO: syntax check the input here
packages_in_scope = stack_config['npms']
else:
packages_in_scope = all_packages
if verbose: if verbose:
print(f'Packages: {packages}') print(f'Packages: {packages_in_scope}')
def build_package(package): def build_package(package):
if not quiet: if not quiet:
@@ -84,7 +99,7 @@ def command(ctx, include, exclude):
else: else:
print("Skipped") print("Skipped")
for package in packages: for package in packages_in_scope:
if include_exclude_check(package, include, exclude): if include_exclude_check(package, include, exclude):
build_package(package) build_package(package)
else: else:
@@ -14,6 +14,12 @@ services:
fixturenet-eth-geth-1: fixturenet-eth-geth-1:
hostname: fixturenet-eth-geth-1 hostname: fixturenet-eth-geth-1
cap_add:
- SYS_PTRACE
environment:
CERC_REMOTE_DEBUG: "true"
CERC_RUN_STATEDIFF: "detect"
CERC_STATEDIFF_DB_NODE_ID: 1
env_file: env_file:
- ../config/fixturenet-eth/fixturenet-eth.env - ../config/fixturenet-eth/fixturenet-eth.env
image: cerc/fixturenet-eth-geth:local image: cerc/fixturenet-eth-geth:local
@@ -27,12 +33,11 @@ services:
- fixturenet-eth-bootnode-geth - fixturenet-eth-bootnode-geth
ports: ports:
- "8545" - "8545"
- "40000"
- "6060"
fixturenet-eth-geth-2: fixturenet-eth-geth-2:
hostname: fixturenet-eth-geth-2 hostname: fixturenet-eth-geth-2
environment:
CERC_RUN_STATEDIFF: "detect"
CERC_STATEDIFF_DB_NODE_ID: 2
healthcheck: healthcheck:
test: ["CMD", "nc", "-v", "localhost", "8545"] test: ["CMD", "nc", "-v", "localhost", "8545"]
interval: 30s interval: 30s
@@ -18,3 +18,4 @@ CERC_STATEDIFF_DB_NAME="cerc_testing"
CERC_STATEDIFF_DB_USER="vdbm" CERC_STATEDIFF_DB_USER="vdbm"
CERC_STATEDIFF_DB_PASSWORD="password" CERC_STATEDIFF_DB_PASSWORD="password"
CERC_STATEDIFF_DB_GOOSE_MIN_VER=23 CERC_STATEDIFF_DB_GOOSE_MIN_VER=23
CERC_STATEDIFF_DB_LOG_STATEMENTS="false"
@@ -1,10 +1,17 @@
FROM skylenet/ethereum-genesis-generator@sha256:210353ce7c898686bc5092f16c61220a76d357f51eff9c451e9ad1b9ad03d4d3 AS ethgen FROM skylenet/ethereum-genesis-generator@sha256:210353ce7c898686bc5092f16c61220a76d357f51eff9c451e9ad1b9ad03d4d3 AS ethgen
FROM cerc/go-ethereum:local # Using the same golang image as used to build geth: https://github.com/cerc-io/go-ethereum/blob/HEAD/Dockerfile
FROM golang:1.18-alpine as delve
RUN go install github.com/go-delve/delve/cmd/dlv@latest
FROM cerc/go-ethereum:local as geth
FROM alpine:latest
RUN apk add --no-cache python3 python3-dev py3-pip curl wget jq build-base gettext libintl openssl bash bind-tools postgresql-client RUN apk add --no-cache python3 python3-dev py3-pip curl wget jq build-base gettext libintl openssl bash bind-tools postgresql-client
COPY --from=ethgen /usr/local/bin/eth2-testnet-genesis /usr/local/bin/eth2-testnet-genesis COPY --from=delve /go/bin/dlv /usr/local/bin/
COPY --from=ethgen /usr/local/bin/eth2-val-tools /usr/local/bin/eth2-val-tools COPY --from=ethgen /usr/local/bin/eth2-testnet-genesis /usr/local/bin/
COPY --from=ethgen /usr/local/bin/eth2-val-tools /usr/local/bin/
COPY --from=ethgen /apps /apps COPY --from=ethgen /apps /apps
RUN cd /apps/el-gen && pip3 install -r requirements.txt RUN cd /apps/el-gen && pip3 install -r requirements.txt
@@ -14,6 +21,7 @@ COPY run-el.sh /opt/testnet/run.sh
RUN cd /opt/testnet && make genesis-el RUN cd /opt/testnet && make genesis-el
COPY --from=geth /usr/local/bin/geth /usr/local/bin/
RUN geth init /opt/testnet/build/el/geth.json && rm -f ~/.ethereum/geth/nodekey RUN geth init /opt/testnet/build/el/geth.json && rm -f ~/.ethereum/geth/nodekey
ENTRYPOINT ["/opt/testnet/run.sh"] ENTRYPOINT ["/opt/testnet/run.sh"]
@@ -9,13 +9,18 @@ cd /opt/testnet/build/el
python3 -m http.server 9898 & python3 -m http.server 9898 &
cd $HOME_DIR cd $HOME_DIR
START_CMD="geth"
if [ "true" == "$CERC_REMOTE_DEBUG" ] && [ -x "/usr/local/bin/dlv" ]; then
START_CMD="/usr/local/bin/dlv --listen=:40000 --headless=true --api-version=2 --accept-multiclient exec /usr/local/bin/geth --continue --"
fi
if [ "true" == "$RUN_BOOTNODE" ]; then if [ "true" == "$RUN_BOOTNODE" ]; then
geth \ $START_CMD \
--nodekeyhex="${BOOTNODE_KEY}" \ --nodekeyhex="${BOOTNODE_KEY}" \
--nodiscover \ --nodiscover \
--ipcdisable \ --ipcdisable \
--networkid=${NETWORK_ID} \ --networkid=${NETWORK_ID} \
--netrestrict="${NETRESTRICT}" 2>&1 | tee /var/log/geth_bootnode.log --netrestrict="${NETRESTRICT}"
else else
cd /opt/testnet/accounts cd /opt/testnet/accounts
./import_keys.sh ./import_keys.sh
@@ -56,17 +61,18 @@ else
--statediff.db.password=$CERC_STATEDIFF_DB_PASSWORD \ --statediff.db.password=$CERC_STATEDIFF_DB_PASSWORD \
--statediff.db.port=$CERC_STATEDIFF_DB_PORT \ --statediff.db.port=$CERC_STATEDIFF_DB_PORT \
--statediff.db.user=$CERC_STATEDIFF_DB_USER \ --statediff.db.user=$CERC_STATEDIFF_DB_USER \
--statediff.db.logstatements=${CERC_STATEDIFF_DB_LOG_STATEMENTS:-false} \
--statediff.waitforsync=true \ --statediff.waitforsync=true \
--statediff.writing=true" --statediff.writing=true"
fi fi
geth \ $START_CMD \
--bootnodes="${ENODE}" \ --bootnodes="${ENODE}" \
--allow-insecure-unlock \ --allow-insecure-unlock \
--http \ --http \
--http.addr="0.0.0.0" \ --http.addr="0.0.0.0" \
--http.vhosts="*" \ --http.vhosts="*" \
--http.api="eth,web3,net,admin,personal" \ --http.api="eth,web3,net,admin,personal,debug,statediff" \
--http.corsdomain="*" \ --http.corsdomain="*" \
--authrpc.addr="0.0.0.0" \ --authrpc.addr="0.0.0.0" \
--authrpc.vhosts="*" \ --authrpc.vhosts="*" \
@@ -79,6 +85,9 @@ else
--syncmode=full \ --syncmode=full \
--mine \ --mine \
--miner.threads=1 \ --miner.threads=1 \
--verbosity=5 \ --metrics \
--miner.etherbase="${ETHERBASE}" ${STATEDIFF_OPTS} 2>&1 | tee /var/log/geth.log --metrics.addr="0.0.0.0" \
--verbosity=${CERC_GETH_VERBOSITY:-3} \
--vmodule="${CERC_GETH_VMODULE:-statediff/*=5}" \
--miner.etherbase="${ETHERBASE}" ${STATEDIFF_OPTS}
fi fi
+112 -112
View File
@@ -1,157 +1,157 @@
# ERC20 Watcher # ERC20 Watcher
Instructions to deploy a local ERC20 watcher stack (core + watcher) for demonstration and testing purposes using [laconic-stack-orchestrator](../../README.md#setup) Instructions to deploy a local ERC20 watcher stack (core + watcher) for demonstration and testing purposes using [stack orchestrator](/README.md#install)
## Setup ## Setup
* Clone / pull required repositories: Clone required repositories:
```bash ```bash
$ laconic-so setup-repositories --include cerc-io/go-ethereum,cerc-io/ipld-eth-db,cerc-io/ipld-eth-server,cerc-io/watcher-ts --pull laconic-so setup-repositories --include cerc-io/go-ethereum,cerc-io/ipld-eth-db,cerc-io/ipld-eth-server,cerc-io/watcher-ts
``` ```
* Build the core and watcher container images: Build the core and watcher container images:
```bash ```bash
$ laconic-so build-containers --include cerc/go-ethereum,cerc/go-ethereum-foundry,cerc/ipld-eth-db,cerc/ipld-eth-server,cerc/watcher-erc20 laconic-so build-containers --include cerc/go-ethereum,cerc/go-ethereum-foundry,cerc/ipld-eth-db,cerc/ipld-eth-server,cerc/watcher-erc20
``` ```
This should create the required docker images in the local image registry. This should create the required docker images in the local image registry.
* Deploy the stack: Deploy the stack:
```bash ```bash
$ laconic-so deploy-system --include db,go-ethereum-foundry,ipld-eth-server,watcher-erc20 up laconic-so deploy-system --include ipld-eth-db,go-ethereum-foundry,ipld-eth-server,watcher-erc20 up
``` ```
## Demo ## Demo
* Find the watcher container's id using `docker ps` and export it for later use: Find the watcher container's id using `docker ps` and export it for later use:
```bash ```bash
$ export CONTAINER_ID=<CONTAINER_ID> export CONTAINER_ID=<CONTAINER_ID>
``` ```
* Deploy an ERC20 token: Deploy an ERC20 token:
```bash ```bash
$ docker exec $CONTAINER_ID yarn token:deploy:docker docker exec $CONTAINER_ID yarn token:deploy:docker
``` ```
Export the address of the deployed token to a shell variable for later use: Export the address of the deployed token to a shell variable for later use:
```bash ```bash
$ export TOKEN_ADDRESS=<TOKEN_ADDRESS> export TOKEN_ADDRESS=<TOKEN_ADDRESS>
``` ```
* Open `http://localhost:3002/graphql` (GraphQL Playground) in a browser window Open `http://localhost:3002/graphql` (GraphQL Playground) in a browser window
* Connect MetaMask to `http://localhost:8545` (with chain ID `99`) Connect MetaMask to `http://localhost:8545` (with chain ID `99`)
* Add the deployed token as an asset in MetaMask and check that the initial balance is zero Add the deployed token as an asset in MetaMask and check that the initial balance is zero
* Export your MetaMask account (second account) address to a shell variable for later use: Export your MetaMask account (second account) address to a shell variable for later use:
```bash ```bash
$ export RECIPIENT_ADDRESS=<RECIPIENT_ADDRESS> export RECIPIENT_ADDRESS=<RECIPIENT_ADDRESS>
``` ```
* To get the primary account's address, run: To get the primary account's address, run:
```bash ```bash
$ docker exec $CONTAINER_ID yarn account:docker docker exec $CONTAINER_ID yarn account:docker
``` ```
* To get the current block hash at any time, run: To get the current block hash at any time, run:
```bash ```bash
$ docker exec $CONTAINER_ID yarn block:latest:docker docker exec $CONTAINER_ID yarn block:latest:docker
``` ```
* Fire a GQL query in the playground to get the name, symbol and total supply of the deployed token: Fire a GQL query in the playground to get the name, symbol and total supply of the deployed token:
```graphql ```graphql
query { query {
name( name(
blockHash: "LATEST_BLOCK_HASH" blockHash: "LATEST_BLOCK_HASH"
token: "TOKEN_ADDRESS" token: "TOKEN_ADDRESS"
) { ) {
value value
proof { proof {
data data
}
}
symbol(
blockHash: "LATEST_BLOCK_HASH"
token: "TOKEN_ADDRESS"
) {
value
proof {
data
}
}
totalSupply(
blockHash: "LATEST_BLOCK_HASH"
token: "TOKEN_ADDRESS"
) {
value
proof {
data
}
} }
} }
```
* Fire the following query to get balances for the primary and the recipient account at the latest block hash: symbol(
blockHash: "LATEST_BLOCK_HASH"
```graphql token: "TOKEN_ADDRESS"
query { ) {
fromBalanceOf: balanceOf( value
blockHash: "LATEST_BLOCK_HASH" proof {
token: "TOKEN_ADDRESS", data
# primary account having all the balance initially
owner: "PRIMARY_ADDRESS"
) {
value
proof {
data
}
}
toBalanceOf: balanceOf(
blockHash: "LATEST_BLOCK_HASH"
token: "TOKEN_ADDRESS",
owner: "RECIPIENT_ADDRESS"
) {
value
proof {
data
}
} }
} }
```
* The initial balance for the primary account should be `1000000000000000000000` totalSupply(
* The initial balance for the recipient should be `0` blockHash: "LATEST_BLOCK_HASH"
token: "TOKEN_ADDRESS"
) {
value
proof {
data
}
}
}
```
* Transfer tokens to the recipient account: Fire the following query to get balances for the primary and the recipient account at the latest block hash:
```bash ```graphql
$ docker exec $CONTAINER_ID yarn token:transfer:docker --token $TOKEN_ADDRESS --to $RECIPIENT_ADDRESS --amount 100 query {
``` fromBalanceOf: balanceOf(
blockHash: "LATEST_BLOCK_HASH"
token: "TOKEN_ADDRESS",
# primary account having all the balance initially
owner: "PRIMARY_ADDRESS"
) {
value
proof {
data
}
}
toBalanceOf: balanceOf(
blockHash: "LATEST_BLOCK_HASH"
token: "TOKEN_ADDRESS",
owner: "RECIPIENT_ADDRESS"
) {
value
proof {
data
}
}
}
```
* Fire the above GQL query again with the latest block hash to get updated balances for the primary (`from`) and the recipient (`to`) account: - The initial balance for the primary account should be `1000000000000000000000`
- The initial balance for the recipient should be `0`
* The balance for the primary account should be reduced by the transfer amount (`100`) Transfer tokens to the recipient account:
* The balance for the recipient account should be equal to the transfer amount (`100`)
* Transfer funds between different accounts using MetaMask and use the playground to query the balance before and after the transfer. ```bash
docker exec $CONTAINER_ID yarn token:transfer:docker --token $TOKEN_ADDRESS --to $RECIPIENT_ADDRESS --amount 100
```
Fire the above GQL query again with the latest block hash to get updated balances for the primary (`from`) and the recipient (`to`) account:
- The balance for the primary account should be reduced by the transfer amount (`100`)
- The balance for the recipient account should be equal to the transfer amount (`100`)
Transfer funds between different accounts using MetaMask and use the playground to query the balance before and after the transfer.
## Clean up ## Clean up
* To stop all the services running in background run: To stop all the services running in background run:
```bash ```bash
$ laconic-so deploy-system --include db,go-ethereum-foundry,ipld-eth-server,watcher-erc20 down laconic-so deploy-system --include ipld-eth-db,go-ethereum-foundry,ipld-eth-server,watcher-erc20 down
``` ```
@@ -1,9 +1,12 @@
version: "1.0" version: "1.0"
name: laconicd-fixturenet name: fixturenet-laconicd
repos: repos:
- cerc-io/laconicd - cerc-io/laconicd
- cerc-io/laconic-sdk - cerc-io/laconic-sdk
- cerc-io/laconic-registry-cli - cerc-io/laconic-registry-cli
npms:
- laconic-sdk
- laconic-registry-cli
containers: containers:
- cerc/laconicd - cerc/laconicd
- cerc/laconic-registry-cli - cerc/laconic-registry-cli
+1 -1
View File
@@ -1,2 +1,2 @@
# This file should be re-generated running: scripts/update-version-file.sh script # This file should be re-generated running: scripts/update-version-file.sh script
v1.0.6-alpha-ae7a17c v1.0.10-alpha-4e1366d
+18 -4
View File
@@ -20,8 +20,9 @@ import os
import sys import sys
from python_on_whales import DockerClient from python_on_whales import DockerClient
import click import click
import importlib import importlib.resources
from pathlib import Path from pathlib import Path
import yaml
from .util import include_exclude_check from .util import include_exclude_check
@@ -40,6 +41,7 @@ def command(ctx, include, exclude, cluster, command, services):
quiet = ctx.obj.quiet quiet = ctx.obj.quiet
verbose = ctx.obj.verbose verbose = ctx.obj.verbose
dry_run = ctx.obj.dry_run dry_run = ctx.obj.dry_run
stack = ctx.obj.stack
# See: https://stackoverflow.com/questions/25389095/python-get-path-of-root-project-structure # See: https://stackoverflow.com/questions/25389095/python-get-path-of-root-project-structure
compose_dir = Path(__file__).absolute().parent.joinpath("data", "compose") compose_dir = Path(__file__).absolute().parent.joinpath("data", "compose")
@@ -56,15 +58,27 @@ def command(ctx, include, exclude, cluster, command, services):
# See: https://stackoverflow.com/a/20885799/1701505 # See: https://stackoverflow.com/a/20885799/1701505
from . import data from . import data
with importlib.resources.open_text(data, "pod-list.txt") as pod_list_file: with importlib.resources.open_text(data, "pod-list.txt") as pod_list_file:
pods = pod_list_file.read().splitlines() all_pods = pod_list_file.read().splitlines()
pods_in_scope = []
if stack:
# In order to be compatible with Python 3.8 we need to use this hack to get the path:
# See: https://stackoverflow.com/questions/25389095/python-get-path-of-root-project-structure
stack_file_path = Path(__file__).absolute().parent.joinpath("data", "stacks", stack, "stack.yml")
with stack_file_path:
stack_config = yaml.safe_load(open(stack_file_path, "r"))
# TODO: syntax check the input here
pods_in_scope = stack_config['pods']
else:
pods_in_scope = all_pods
if verbose: if verbose:
print(f"Pods: {pods}") print(f"Pods: {pods_in_scope}")
# Construct a docker compose command suitable for our purpose # Construct a docker compose command suitable for our purpose
compose_files = [] compose_files = []
for pod in pods: for pod in pods_in_scope:
if include_exclude_check(pod, include, exclude): if include_exclude_check(pod, include, exclude):
compose_file_name = os.path.join(compose_dir, f"docker-compose-{pod}.yml") compose_file_name = os.path.join(compose_dir, f"docker-compose-{pod}.yml")
compose_files.append(compose_file_name) compose_files.append(compose_file_name)
+21 -3
View File
@@ -22,7 +22,9 @@ from decouple import config
import git import git
from tqdm import tqdm from tqdm import tqdm
import click import click
import importlib import importlib.resources
from pathlib import Path
import yaml
from .util import include_exclude_check from .util import include_exclude_check
@@ -64,9 +66,11 @@ def command(ctx, include, exclude, git_ssh, check_only, pull, branches_file):
quiet = ctx.obj.quiet quiet = ctx.obj.quiet
verbose = ctx.obj.verbose verbose = ctx.obj.verbose
dry_run = ctx.obj.dry_run dry_run = ctx.obj.dry_run
stack = ctx.obj.stack
branches = [] branches = []
# TODO: branches file needs to be re-worked in the context of stacks
if branches_file: if branches_file:
if verbose: if verbose:
print(f"loading branches from: {branches_file}") print(f"loading branches from: {branches_file}")
@@ -96,11 +100,25 @@ def command(ctx, include, exclude, git_ssh, check_only, pull, branches_file):
with importlib.resources.open_text(data, "repository-list.txt") as repository_list_file: with importlib.resources.open_text(data, "repository-list.txt") as repository_list_file:
all_repos = repository_list_file.read().splitlines() all_repos = repository_list_file.read().splitlines()
repos_in_scope = []
if stack:
# In order to be compatible with Python 3.8 we need to use this hack to get the path:
# See: https://stackoverflow.com/questions/25389095/python-get-path-of-root-project-structure
stack_file_path = Path(__file__).absolute().parent.joinpath("data", "stacks", stack, "stack.yml")
with stack_file_path:
stack_config = yaml.safe_load(open(stack_file_path, "r"))
# TODO: syntax check the input here
repos_in_scope = stack_config['repos']
else:
repos_in_scope = all_repos
if verbose: if verbose:
print(f"Repos: {all_repos}") print(f"Repos: {repos_in_scope}")
if stack:
print(f"Stack: {stack}")
repos = [] repos = []
for repo in all_repos: for repo in repos_in_scope:
if include_exclude_check(repo, include, exclude): if include_exclude_check(repo, include, exclude):
repos.append(repo) repos.append(repo)
else: else:
+1 -1
View File
@@ -14,7 +14,7 @@
# along with this program. If not, see <http:#www.gnu.org/licenses/>. # along with this program. If not, see <http:#www.gnu.org/licenses/>.
import click import click
import importlib import importlib.resources
@click.command() @click.command()
@click.pass_context @click.pass_context
-4
View File
@@ -1,4 +0,0 @@
# Builds the shiv "package" for distribution
# TODO: add build version/tag to filename
# TODO: add version info to code for version subcommand
shiv -c laconic-so -o package/laconic-so .
+7 -3
View File
@@ -24,8 +24,11 @@ from app import version
CONTEXT_SETTINGS = dict(help_option_names=['-h', '--help']) CONTEXT_SETTINGS = dict(help_option_names=['-h', '--help'])
# TODO: this seems kind of weird and heavy on boilerplate -- check it is
# the best Python can do for us.
class Options(object): class Options(object):
def __init__(self, quiet, verbose, dry_run, local_stack, debug): def __init__(self, stack, quiet, verbose, dry_run, local_stack, debug):
self.stack = stack
self.quiet = quiet self.quiet = quiet
self.verbose = verbose self.verbose = verbose
self.dry_run = dry_run self.dry_run = dry_run
@@ -34,6 +37,7 @@ class Options(object):
@click.group(context_settings=CONTEXT_SETTINGS) @click.group(context_settings=CONTEXT_SETTINGS)
@click.option('--stack', help="specify a stack to build/deploy")
@click.option('--quiet', is_flag=True, default=False) @click.option('--quiet', is_flag=True, default=False)
@click.option('--verbose', is_flag=True, default=False) @click.option('--verbose', is_flag=True, default=False)
@click.option('--dry-run', is_flag=True, default=False) @click.option('--dry-run', is_flag=True, default=False)
@@ -41,9 +45,9 @@ class Options(object):
@click.option('--debug', is_flag=True, default=False) @click.option('--debug', is_flag=True, default=False)
# See: https://click.palletsprojects.com/en/8.1.x/complex/#building-a-git-clone # See: https://click.palletsprojects.com/en/8.1.x/complex/#building-a-git-clone
@click.pass_context @click.pass_context
def cli(ctx, quiet, verbose, dry_run, local_stack, debug): def cli(ctx, stack, quiet, verbose, dry_run, local_stack, debug):
"""Laconic Stack Orchestrator""" """Laconic Stack Orchestrator"""
ctx.obj = Options(quiet, verbose, dry_run, local_stack, debug) ctx.obj = Options(stack, quiet, verbose, dry_run, local_stack, debug)
cli.add_command(setup_repositories.command, "setup-repositories") cli.add_command(setup_repositories.command, "setup-repositories")
+3
View File
@@ -0,0 +1,3 @@
# laconic-so
Sub-commands and flags
@@ -0,0 +1 @@
8f6452ed13e85a447103a7fff7cf3fb8ff5ea51a
+37
View File
@@ -0,0 +1,37 @@
# Spec
TODO: update
## Implementation
The orchestrator's operation is driven by files shown below. `repository-list.txt` container the list of git repositories; `container-image-list.txt` contains
the list of container image names, while `clister-list.txt` specifies the set of compose components (corresponding to individual docker-compose-xxx.yml files which may in turn specify more than one container).
Files required to build each container image are stored under `./container-build/<container-name>`
Files required at deploy-time are stored under `./config/<component-name>`
```
├── pod-list.txt
├── compose
│   ├── docker-compose-contract.yml
│   ├── docker-compose-db-sharding.yml
│   ├── docker-compose-db.yml
│   ├── docker-compose-eth-statediff-fill-service.yml
│   ├── docker-compose-go-ethereum-foundry.yml
│   ├── docker-compose-ipld-eth-beacon-db.yml
│   ├── docker-compose-ipld-eth-beacon-indexer.yml
│   ├── docker-compose-ipld-eth-server.yml
│   ├── docker-compose-lighthouse.yml
│   └── docker-compose-prometheus-grafana.yml
├── config
│   └── ipld-eth-server
├── container-build
│   ├── cerc-eth-statediff-fill-service
│   ├── cerc-go-ethereum
│   ├── cerc-go-ethereum-foundry
│   ├── cerc-ipld-eth-beacon-db
│   ├── cerc-ipld-eth-beacon-indexer
│   ├── cerc-ipld-eth-db
│   ├── cerc-ipld-eth-server
│   ├── cerc-lighthouse
│   └── cerc-test-contract
├── container-image-list.txt
├── repository-list.txt
```
+1
View File
@@ -3,3 +3,4 @@ GitPython>=3.1.27
tqdm>=4.64.0 tqdm>=4.64.0
python-on-whales>=0.52.0 python-on-whales>=0.52.0
click>=8.1.3 click>=8.1.3
pyyaml>=6.0
+1
View File
@@ -1,3 +1,4 @@
# Builds the shiv "package" for distribution # Builds the shiv "package" for distribution
mkdir -p ./package
version_string=$( ./scripts/update_version_file.sh) version_string=$( ./scripts/update_version_file.sh)
shiv -c laconic-so -o package/laconic-so-${version_string} . shiv -c laconic-so -o package/laconic-so-${version_string} .
+2 -2
View File
@@ -6,7 +6,7 @@ with open("requirements.txt", "r", encoding="utf-8") as fh:
requirements = fh.read() requirements = fh.read()
setup( setup(
name='laconic-stack-orchestrator', name='laconic-stack-orchestrator',
version='0.0.5', version='1.0.9',
author='Cerc', author='Cerc',
author_email='info@cerc.io', author_email='info@cerc.io',
license='GNU Affero General Public License', license='GNU Affero General Public License',
@@ -20,7 +20,7 @@ setup(
python_requires='>=3.7', python_requires='>=3.7',
include_package_data=True, include_package_data=True,
# See: https://github.com/pypa/setuptools/issues/1806 # See: https://github.com/pypa/setuptools/issues/1806
package_data={'': ['data/*', 'data/*/*', 'data/*/*/*']}, package_data={'': ['data/*', 'data/*/*', 'data/*/*/*', 'data/*/*/*/*', 'data/*/*/*/*/*']},
classifiers=[ classifiers=[
"Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.8",
"Operating System :: OS Independent", "Operating System :: OS Independent",