forked from cerc-io/stack-orchestrator
Compare commits
59
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
811bbd9db4 | ||
|
|
8d9682eb47 | ||
|
|
638435873c | ||
|
|
97a85359ff | ||
|
|
ffa00767d4 | ||
|
|
86462c940f | ||
|
|
87db167d7f | ||
|
|
dd856af2d3 | ||
|
|
cd3d908d0d | ||
|
|
03f9acf869 | ||
|
|
ba1aad9fa6 | ||
|
|
dc36a6564a | ||
|
|
c5c3fc1618 | ||
|
|
2e384b7179 | ||
|
|
b708836aa9 | ||
|
|
d8da9b6515 | ||
|
|
5a1399f2b2 | ||
|
|
89db6e1e92 | ||
|
|
9bd59f29d9 | ||
|
|
8afae1904b | ||
|
|
7acabb0743 | ||
|
|
34f3b719e4 | ||
|
|
0e814bd4da | ||
|
|
873a6d472c | ||
|
|
39df4683ac | ||
|
|
23ca4c4341 | ||
|
|
f64ef5d128 | ||
|
|
5f8e809b2d | ||
|
|
4a7df2de33 | ||
|
|
0c47da42fe | ||
|
|
e290c62aca | ||
|
|
f1fdc48aaa | ||
|
|
a54072de6c | ||
|
|
fa21ff2627 | ||
|
|
33d395e213 | ||
|
|
75ff60752a | ||
|
|
44b9709717 | ||
|
|
e56da7dcc1 | ||
|
|
60d34217f8 | ||
|
|
952389abb0 | ||
|
|
5c275aa622 | ||
|
|
8576137557 | ||
|
|
65c1cdf6b1 | ||
|
|
265699bc38 | ||
|
|
4a7670a5d6 | ||
|
|
6087e1cd31 | ||
|
|
1def279d26 | ||
|
|
64691bd206 | ||
|
|
aef5986135 | ||
|
|
6f8f0340d3 | ||
|
|
7590d6e237 | ||
|
|
573f99dbbe | ||
|
|
8052c1c25e | ||
|
|
a674d13493 | ||
|
|
0d4f4509c8 | ||
|
|
5af27b1b3a | ||
|
|
6c91b87348 | ||
|
|
7d18334953 | ||
|
|
79c1c5ed99 |
@@ -1,57 +0,0 @@
|
||||
name: Fixturenet-Eth-Plugeth-Test
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: '*'
|
||||
paths:
|
||||
- '!**'
|
||||
- '.gitea/workflows/triggers/fixturenet-eth-plugeth-test'
|
||||
schedule: # Note: coordinate with other tests to not overload runners at the same time of day
|
||||
- cron: '2 14 * * *'
|
||||
|
||||
|
||||
jobs:
|
||||
test:
|
||||
name: "Run an Ethereum plugeth fixturenet test"
|
||||
runs-on: ubuntu-latest
|
||||
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: "Run fixturenet-eth tests"
|
||||
run: ./tests/fixturenet-eth-plugeth/run-test.sh
|
||||
- name: Notify Vulcanize Slack on CI failure
|
||||
if: ${{ always() && github.ref_name == 'main' }}
|
||||
uses: ravsamhq/notify-slack-action@v2
|
||||
with:
|
||||
status: ${{ job.status }}
|
||||
notify_when: 'failure'
|
||||
env:
|
||||
SLACK_WEBHOOK_URL: ${{ secrets.VULCANIZE_SLACK_CI_ALERTS }}
|
||||
- name: Notify DeepStack Slack on CI failure
|
||||
if: ${{ always() && github.ref_name == 'main' }}
|
||||
uses: ravsamhq/notify-slack-action@v2
|
||||
with:
|
||||
status: ${{ job.status }}
|
||||
notify_when: 'failure'
|
||||
env:
|
||||
SLACK_WEBHOOK_URL: ${{ secrets.DEEPSTACK_SLACK_CI_ALERTS }}
|
||||
@@ -1,55 +0,0 @@
|
||||
name: Fixturenet-Eth-Test
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: '*'
|
||||
paths:
|
||||
- '!**'
|
||||
- '.gitea/workflows/triggers/fixturenet-eth-test'
|
||||
|
||||
|
||||
jobs:
|
||||
test:
|
||||
name: "Run an Ethereum fixturenet test"
|
||||
runs-on: ubuntu-latest
|
||||
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: "Run fixturenet-eth tests"
|
||||
run: ./tests/fixturenet-eth/run-test.sh
|
||||
- name: Notify Vulcanize Slack on CI failure
|
||||
if: ${{ always() && github.ref_name == 'main' }}
|
||||
uses: ravsamhq/notify-slack-action@v2
|
||||
with:
|
||||
status: ${{ job.status }}
|
||||
notify_when: 'failure'
|
||||
env:
|
||||
SLACK_WEBHOOK_URL: ${{ secrets.VULCANIZE_SLACK_CI_ALERTS }}
|
||||
- name: Notify DeepStack Slack on CI failure
|
||||
if: ${{ always() && github.ref_name == 'main' }}
|
||||
uses: ravsamhq/notify-slack-action@v2
|
||||
with:
|
||||
status: ${{ job.status }}
|
||||
notify_when: 'failure'
|
||||
env:
|
||||
SLACK_WEBHOOK_URL: ${{ secrets.DEEPSTACK_SLACK_CI_ALERTS }}
|
||||
@@ -39,7 +39,7 @@ jobs:
|
||||
- name: "Print Python version"
|
||||
run: python3 --version
|
||||
- name: "Install shiv"
|
||||
run: pip install shiv
|
||||
run: pip install shiv==1.0.6
|
||||
- name: "Generate build version file"
|
||||
run: ./scripts/create_build_tag_file.sh
|
||||
- name: "Build local shiv package"
|
||||
|
||||
@@ -35,7 +35,7 @@ jobs:
|
||||
- name: "Print Python version"
|
||||
run: python3 --version
|
||||
- name: "Install shiv"
|
||||
run: pip install shiv
|
||||
run: pip install shiv==1.0.6
|
||||
- name: "Build local shiv package"
|
||||
id: build
|
||||
run: |
|
||||
|
||||
@@ -33,7 +33,7 @@ jobs:
|
||||
- name: "Print Python version"
|
||||
run: python3 --version
|
||||
- name: "Install shiv"
|
||||
run: pip install shiv
|
||||
run: pip install shiv==1.0.6
|
||||
- name: "Generate build version file"
|
||||
run: ./scripts/create_build_tag_file.sh
|
||||
- name: "Build local shiv package"
|
||||
|
||||
@@ -33,7 +33,7 @@ jobs:
|
||||
- name: "Print Python version"
|
||||
run: python3 --version
|
||||
- name: "Install shiv"
|
||||
run: pip install shiv
|
||||
run: pip install shiv==1.0.6
|
||||
- name: "Generate build version file"
|
||||
run: ./scripts/create_build_tag_file.sh
|
||||
- name: "Build local shiv package"
|
||||
|
||||
@@ -33,7 +33,7 @@ jobs:
|
||||
- name: "Print Python version"
|
||||
run: python3 --version
|
||||
- name: "Install shiv"
|
||||
run: pip install shiv
|
||||
run: pip install shiv==1.0.6
|
||||
- name: "Generate build version file"
|
||||
run: ./scripts/create_build_tag_file.sh
|
||||
- name: "Build local shiv package"
|
||||
|
||||
@@ -33,7 +33,7 @@ jobs:
|
||||
- name: "Print Python version"
|
||||
run: python3 --version
|
||||
- name: "Install shiv"
|
||||
run: pip install shiv
|
||||
run: pip install shiv==1.0.6
|
||||
- name: "Generate build version file"
|
||||
run: ./scripts/create_build_tag_file.sh
|
||||
- name: "Build local shiv package"
|
||||
|
||||
@@ -35,7 +35,7 @@ jobs:
|
||||
- name: "Print Python version"
|
||||
run: python3 --version
|
||||
- name: "Install shiv"
|
||||
run: pip install shiv
|
||||
run: pip install shiv==1.0.6
|
||||
- name: "Generate build version file"
|
||||
run: ./scripts/create_build_tag_file.sh
|
||||
- name: "Build local shiv package"
|
||||
|
||||
+21
-9
@@ -1,19 +1,22 @@
|
||||
name: Fixturenet-Eth-Plugeth-Arm-Test
|
||||
name: K8s Deployment Control Test
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches: '*'
|
||||
push:
|
||||
branches: '*'
|
||||
paths:
|
||||
- '!**'
|
||||
- '.gitea/workflows/triggers/fixturenet-eth-plugeth-arm-test'
|
||||
- '.gitea/workflows/triggers/test-k8s-deployment-control'
|
||||
- '.gitea/workflows/test-k8s-deployment-control.yml'
|
||||
- 'tests/k8s-deployment-control/run-test.sh'
|
||||
schedule: # Note: coordinate with other tests to not overload runners at the same time of day
|
||||
- cron: '2 14 * * *'
|
||||
|
||||
- cron: '3 30 * * *'
|
||||
|
||||
jobs:
|
||||
test:
|
||||
name: "Run an Ethereum plugeth fixturenet test"
|
||||
runs-on: ubuntu-latest-arm
|
||||
name: "Run deployment control suite on kind/k8s"
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: "Clone project repository"
|
||||
uses: actions/checkout@v3
|
||||
@@ -32,13 +35,22 @@ jobs:
|
||||
- name: "Print Python version"
|
||||
run: python3 --version
|
||||
- name: "Install shiv"
|
||||
run: pip install shiv
|
||||
run: pip install shiv==1.0.6
|
||||
- name: "Generate build version file"
|
||||
run: ./scripts/create_build_tag_file.sh
|
||||
- name: "Build local shiv package"
|
||||
run: ./scripts/build_shiv_package.sh
|
||||
- name: "Run fixturenet-eth tests"
|
||||
run: ./tests/fixturenet-eth-plugeth/run-test.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 k8s deployment control test"
|
||||
run: |
|
||||
source /opt/bash-utils/cgroup-helper.sh
|
||||
join_cgroup
|
||||
./tests/k8s-deployment-control/run-test.sh
|
||||
- name: Notify Vulcanize Slack on CI failure
|
||||
if: ${{ always() && github.ref_name == 'main' }}
|
||||
uses: ravsamhq/notify-slack-action@v2
|
||||
@@ -32,7 +32,7 @@ jobs:
|
||||
- name: "Print Python version"
|
||||
run: python3 --version
|
||||
- name: "Install shiv"
|
||||
run: pip install shiv
|
||||
run: pip install shiv==1.0.6
|
||||
- name: "Generate build version file"
|
||||
run: ./scripts/create_build_tag_file.sh
|
||||
- name: "Build local shiv package"
|
||||
|
||||
@@ -33,7 +33,7 @@ jobs:
|
||||
- name: "Print Python version"
|
||||
run: python3 --version
|
||||
- name: "Install shiv"
|
||||
run: pip install shiv
|
||||
run: pip install shiv==1.0.6
|
||||
- name: "Generate build version file"
|
||||
run: ./scripts/create_build_tag_file.sh
|
||||
- name: "Build local shiv package"
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
Change this file to trigger running the fixturenet-eth-plugeth-arm-test CI job
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
Change this file to trigger running the fixturenet-eth-plugeth-test CI job
|
||||
trigger
|
||||
trigger
|
||||
@@ -1,2 +0,0 @@
|
||||
Change this file to trigger running the fixturenet-eth-test CI job
|
||||
|
||||
@@ -7,3 +7,4 @@ Trigger
|
||||
Trigger
|
||||
Trigger
|
||||
Trigger
|
||||
Trigger
|
||||
|
||||
@@ -1 +1,3 @@
|
||||
Change this file to trigger running the test-container-registry CI job
|
||||
Change this file to trigger running the test-container-registry CI job
|
||||
Triggered: 2026-01-21
|
||||
Triggered: 2026-01-21 19:28:29
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
Change this file to trigger running the test-database CI job
|
||||
Trigger test run
|
||||
Trigger test run
|
||||
|
||||
@@ -1,2 +1 @@
|
||||
Change this file to trigger running the fixturenet-eth-test CI job
|
||||
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
repos:
|
||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||
rev: v5.0.0
|
||||
hooks:
|
||||
- id: trailing-whitespace
|
||||
- id: end-of-file-fixer
|
||||
- id: check-yaml
|
||||
args: ['--allow-multiple-documents']
|
||||
- id: check-json
|
||||
- id: check-merge-conflict
|
||||
- id: check-added-large-files
|
||||
|
||||
- repo: https://github.com/psf/black
|
||||
rev: 23.12.1
|
||||
hooks:
|
||||
- id: black
|
||||
language_version: python3
|
||||
|
||||
- repo: https://github.com/PyCQA/flake8
|
||||
rev: 7.1.1
|
||||
hooks:
|
||||
- id: flake8
|
||||
args: ['--max-line-length=88', '--extend-ignore=E203,W503,E402']
|
||||
|
||||
- repo: https://github.com/RobertCraigie/pyright-python
|
||||
rev: v1.1.345
|
||||
hooks:
|
||||
- id: pyright
|
||||
|
||||
- repo: https://github.com/adrienverge/yamllint
|
||||
rev: v1.35.1
|
||||
hooks:
|
||||
- id: yamllint
|
||||
args: [-d, relaxed]
|
||||
@@ -0,0 +1,50 @@
|
||||
# CLAUDE.md
|
||||
|
||||
This file provides guidance to Claude Code when working with the stack-orchestrator project.
|
||||
|
||||
## Some rules to follow
|
||||
NEVER speculate about the cause of something
|
||||
NEVER assume your hypotheses are true without evidence
|
||||
|
||||
ALWAYS clearly state when something is a hypothesis
|
||||
ALWAYS use evidence from the systems your interacting with to support your claims and hypotheses
|
||||
|
||||
## Key Principles
|
||||
|
||||
### Development Guidelines
|
||||
- **Single responsibility** - Each component has one clear purpose
|
||||
- **Fail fast** - Let errors propagate, don't hide failures
|
||||
- **DRY/KISS** - Minimize duplication and complexity
|
||||
|
||||
## Development Philosophy: Conversational Literate Programming
|
||||
|
||||
### Approach
|
||||
This project follows principles inspired by literate programming, where development happens through explanatory conversation rather than code-first implementation.
|
||||
|
||||
### Core Principles
|
||||
- **Documentation-First**: All changes begin with discussion of intent and reasoning
|
||||
- **Narrative-Driven**: Complex systems are explained through conversational exploration
|
||||
- **Justification Required**: Every coding task must have a corresponding TODO.md item explaining the "why"
|
||||
- **Iterative Understanding**: Architecture and implementation evolve through dialogue
|
||||
|
||||
### Working Method
|
||||
1. **Explore and Understand**: Read existing code to understand current state
|
||||
2. **Discuss Architecture**: Workshop complex design decisions through conversation
|
||||
3. **Document Intent**: Update TODO.md with clear justification before coding
|
||||
4. **Explain Changes**: Each modification includes reasoning and context
|
||||
5. **Maintain Narrative**: Conversations serve as living documentation of design evolution
|
||||
|
||||
### Implementation Guidelines
|
||||
- Treat conversations as primary documentation
|
||||
- Explain architectural decisions before implementing
|
||||
- Use TODO.md as the "literate document" that justifies all work
|
||||
- Maintain clear narrative threads across sessions
|
||||
- Workshop complex ideas before coding
|
||||
|
||||
This approach treats the human-AI collaboration as a form of **conversational literate programming** where understanding emerges through dialogue before code implementation.
|
||||
|
||||
## Insights and Observations
|
||||
|
||||
### Design Principles
|
||||
- **When something times out that doesn't mean it needs a longer timeout it means something that was expected never happened, not that we need to wait longer for it.**
|
||||
- **NEVER change a timeout because you believe something truncated, you don't understand timeouts, don't edit them unless told to explicitly by user.**
|
||||
@@ -658,4 +658,4 @@
|
||||
You should also get your employer (if you work as a programmer) or school,
|
||||
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||
For more information on this, and how to apply and follow the GNU AGPL, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
<http://www.gnu.org/licenses/>.
|
||||
|
||||
@@ -26,7 +26,7 @@ curl -SL https://github.com/docker/compose/releases/download/v2.11.2/docker-comp
|
||||
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
|
||||
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:
|
||||
@@ -78,5 +78,3 @@ See the [CONTRIBUTING.md](/docs/CONTRIBUTING.md) for developer mode install.
|
||||
## Platform Support
|
||||
|
||||
Native aarm64 is _not_ currently supported. x64 emulation on ARM64 macos should work (not yet tested).
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
# TODO
|
||||
|
||||
## Features Needed
|
||||
|
||||
### Update Stack Command
|
||||
We need an "update stack" command in stack orchestrator and cleaner documentation regarding how to do continuous deployment with and without payments.
|
||||
|
||||
**Context**: Currently, `deploy init` generates a spec file and `deploy create` creates a deployment directory. The `deployment update` command (added by Thomas Lackey) only syncs env vars and restarts - it doesn't regenerate configurations. There's a gap in the workflow for updating stack configurations after initial deployment.
|
||||
|
||||
## Architecture Refactoring
|
||||
|
||||
### Separate Deployer from Stack Orchestrator CLI
|
||||
The deployer logic should be decoupled from the CLI tool to allow independent development and reuse.
|
||||
|
||||
### Separate Stacks from Stack Orchestrator Repo
|
||||
Stacks should live in their own repositories, not bundled with the orchestrator tool. This allows stacks to evolve independently and be maintained by different teams.
|
||||
@@ -1,9 +1,9 @@
|
||||
# Fetching pre-built container images
|
||||
When Stack Orchestrator deploys a stack containing a suite of one or more containers it expects images for those containers to be on the local machine with a tag of the form `<image-name>:local` Images for these containers can be built from source (and optionally base container images from public registries) with the `build-containers` subcommand.
|
||||
When Stack Orchestrator deploys a stack containing a suite of one or more containers it expects images for those containers to be on the local machine with a tag of the form `<image-name>:local` Images for these containers can be built from source (and optionally base container images from public registries) with the `build-containers` subcommand.
|
||||
|
||||
However, the task of building a large number of containers from source may consume considerable time and machine resources. This is where the `fetch-containers` subcommand steps in. It is designed to work exactly like `build-containers` but instead the images, pre-built, are fetched from an image registry then re-tagged for deployment. It can be used in place of `build-containers` for any stack provided the necessary containers, built for the local machine architecture (e.g. arm64 or x86-64) have already been published in an image registry.
|
||||
## Usage
|
||||
To use `fetch-containers`, provide an image registry path, a username and token/password with read access to the registry, and optionally specify `--force-local-overwrite`. If this argument is not specified, if there is already a locally built or previously fetched image for a stack container on the machine, it will not be overwritten and a warning issued.
|
||||
```
|
||||
$ laconic-so --stack mobymask-v3-demo fetch-containers --image-registry git.vdb.to/cerc-io --registry-username <registry-user> --registry-token <registry-token> --force-local-overwrite
|
||||
```
|
||||
```
|
||||
|
||||
@@ -7,7 +7,7 @@ Deploy a local Gitea server, publish NPM packages to it, then use those packages
|
||||
```bash
|
||||
laconic-so --stack build-support build-containers
|
||||
laconic-so --stack package-registry setup-repositories
|
||||
laconic-so --stack package-registry build-containers
|
||||
laconic-so --stack package-registry build-containers
|
||||
laconic-so --stack package-registry deploy up
|
||||
```
|
||||
|
||||
|
||||
@@ -0,0 +1,113 @@
|
||||
# Helm Chart Generation
|
||||
|
||||
Generate Kubernetes Helm charts from stack compose files using Kompose.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
Install Kompose:
|
||||
|
||||
```bash
|
||||
# Linux
|
||||
curl -L https://github.com/kubernetes/kompose/releases/download/v1.34.0/kompose-linux-amd64 -o kompose
|
||||
chmod +x kompose
|
||||
sudo mv kompose /usr/local/bin/
|
||||
|
||||
# macOS
|
||||
brew install kompose
|
||||
|
||||
# Verify
|
||||
kompose version
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
### 1. Create spec file
|
||||
|
||||
```bash
|
||||
laconic-so --stack <stack-name> deploy --deploy-to k8s init \
|
||||
--kube-config ~/.kube/config \
|
||||
--output spec.yml
|
||||
```
|
||||
|
||||
### 2. Generate Helm chart
|
||||
|
||||
```bash
|
||||
laconic-so --stack <stack-name> deploy create \
|
||||
--spec-file spec.yml \
|
||||
--deployment-dir my-deployment \
|
||||
--helm-chart
|
||||
```
|
||||
|
||||
### 3. Deploy to Kubernetes
|
||||
|
||||
```bash
|
||||
helm install my-release my-deployment/chart
|
||||
kubectl get pods -n zenith
|
||||
```
|
||||
|
||||
## Output Structure
|
||||
|
||||
```bash
|
||||
my-deployment/
|
||||
├── spec.yml # Reference
|
||||
├── stack.yml # Reference
|
||||
└── chart/ # Helm chart
|
||||
├── Chart.yaml
|
||||
├── README.md
|
||||
└── templates/
|
||||
└── *.yaml
|
||||
```
|
||||
|
||||
## Example
|
||||
|
||||
```bash
|
||||
# Generate chart for stage1-zenithd
|
||||
laconic-so --stack stage1-zenithd deploy --deploy-to k8s init \
|
||||
--kube-config ~/.kube/config \
|
||||
--output stage1-spec.yml
|
||||
|
||||
laconic-so --stack stage1-zenithd deploy create \
|
||||
--spec-file stage1-spec.yml \
|
||||
--deployment-dir stage1-deployment \
|
||||
--helm-chart
|
||||
|
||||
# Deploy
|
||||
helm install stage1-zenithd stage1-deployment/chart
|
||||
```
|
||||
|
||||
## Production Deployment (TODO)
|
||||
|
||||
### Local Development
|
||||
|
||||
```bash
|
||||
# Access services using port-forward
|
||||
kubectl port-forward service/zenithd 26657:26657
|
||||
kubectl port-forward service/nginx-api-proxy 1317:80
|
||||
kubectl port-forward service/cosmos-explorer 4173:4173
|
||||
```
|
||||
|
||||
### Production Access Options
|
||||
|
||||
- Option 1: Ingress + cert-manager (Recommended)
|
||||
- Install ingress-nginx + cert-manager
|
||||
- Point DNS to cluster LoadBalancer IP
|
||||
- Auto-provisions Let's Encrypt TLS certs
|
||||
- Access: `https://api.zenith.example.com`
|
||||
- Option 2: Cloud LoadBalancer
|
||||
- Use cloud provider's LoadBalancer service type
|
||||
- Point DNS to assigned external IP
|
||||
- Manual TLS cert management
|
||||
- Option 3: Bare Metal (MetalLB + Ingress)
|
||||
- MetalLB provides LoadBalancer IPs from local network
|
||||
- Same Ingress setup as cloud
|
||||
- Option 4: NodePort + External Proxy
|
||||
- Expose services on 30000-32767 range
|
||||
- External nginx/Caddy proxies 80/443 → NodePort
|
||||
- Manual cert management
|
||||
|
||||
### Changes Needed
|
||||
|
||||
- Add Ingress template to charts
|
||||
- Add TLS configuration to values.yaml
|
||||
- Document cert-manager setup
|
||||
- Add production deployment guide
|
||||
@@ -0,0 +1,26 @@
|
||||
# K8S Deployment Enhancements
|
||||
## Controlling pod placement
|
||||
The placement of pods created as part of a stack deployment can be controlled to either avoid certain nodes, or require certain nodes.
|
||||
### Pod/Node Affinity
|
||||
Node affinity rules applied to pods target node labels. The effect is that a pod can only be placed on a node having the specified label value. Note that other pods that do not have any node affinity rules can also be placed on those same nodes. Thus node affinity for a pod controls where that pod can be placed, but does not control where other pods are placed.
|
||||
|
||||
Node affinity for stack pods is specified in the deployment's `spec.yml` file as follows:
|
||||
```
|
||||
node-affinities:
|
||||
- label: nodetype
|
||||
value: typeb
|
||||
```
|
||||
This example denotes that the stack's pods should only be placed on nodes that have the label `nodetype` with value `typeb`.
|
||||
### Node Taint Toleration
|
||||
K8s nodes can be given one or more "taints". These are special fields (distinct from labels) with a name (key) and optional value.
|
||||
When placing pods, the k8s scheduler will only assign a pod to a tainted node if the pod posesses a corresponding "toleration".
|
||||
This is metadata associated with the pod that specifies that the pod "tolerates" a given taint.
|
||||
Therefore taint toleration provides a mechanism by which only certain pods can be placed on specific nodes, and provides a complementary mechanism to node affinity.
|
||||
|
||||
Taint toleration for stack pods is specified in the deployment's `spec.yml` file as follows:
|
||||
```
|
||||
node-tolerations:
|
||||
- key: nodetype
|
||||
value: typeb
|
||||
```
|
||||
This example denotes that the stack's pods will tolerate a taint: `nodetype=typeb`
|
||||
@@ -26,4 +26,3 @@ $ ./scripts/tag_new_release.sh 1 0 17
|
||||
$ ./scripts/build_shiv_package.sh
|
||||
$ ./scripts/publish_shiv_package_github.sh 1 0 17
|
||||
```
|
||||
|
||||
|
||||
+2
-2
@@ -4,9 +4,9 @@ Note: this page is out of date (but still useful) - it will no longer be useful
|
||||
|
||||
## Implementation
|
||||
|
||||
The orchestrator's operation is driven by files shown below.
|
||||
The orchestrator's operation is driven by files shown below.
|
||||
|
||||
- `repository-list.txt` contains the list of git repositories;
|
||||
- `repository-list.txt` contains the list of git repositories;
|
||||
- `container-image-list.txt` contains the list of container image names
|
||||
- `pod-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).
|
||||
- `container-build/` contains the files required to build each container image
|
||||
|
||||
+1
-1
@@ -7,7 +7,7 @@ compilation and static page generation are separated in the `build-webapp` and `
|
||||
|
||||
This offers much more flexibilty than standard Next.js build methods, since any environment variables accessed
|
||||
via `process.env`, whether for pages or for API, will have values drawn from their runtime deployment environment,
|
||||
not their build environment.
|
||||
not their build environment.
|
||||
|
||||
## Building
|
||||
|
||||
|
||||
+110
@@ -0,0 +1,110 @@
|
||||
[build-system]
|
||||
requires = ["setuptools>=61.0", "wheel"]
|
||||
build-backend = "setuptools.build_meta"
|
||||
|
||||
[project]
|
||||
name = "laconic-stack-orchestrator"
|
||||
version = "1.1.0"
|
||||
description = "Orchestrates deployment of the Laconic stack"
|
||||
readme = "README.md"
|
||||
license = {text = "GNU Affero General Public License"}
|
||||
authors = [
|
||||
{name = "Cerc", email = "info@cerc.io"}
|
||||
]
|
||||
requires-python = ">=3.8"
|
||||
classifiers = [
|
||||
"Programming Language :: Python :: 3.8",
|
||||
"Operating System :: OS Independent",
|
||||
]
|
||||
dependencies = [
|
||||
"python-decouple>=3.8",
|
||||
"python-dotenv==1.0.0",
|
||||
"GitPython>=3.1.32",
|
||||
"tqdm>=4.65.0",
|
||||
"python-on-whales>=0.64.0",
|
||||
"click>=8.1.6",
|
||||
"PyYAML>=6.0.1",
|
||||
"ruamel.yaml>=0.17.32",
|
||||
"pydantic==1.10.9",
|
||||
"tomli==2.0.1",
|
||||
"validators==0.22.0",
|
||||
"kubernetes>=28.1.0",
|
||||
"humanfriendly>=10.0",
|
||||
"python-gnupg>=0.5.2",
|
||||
"requests>=2.3.2",
|
||||
]
|
||||
|
||||
[project.optional-dependencies]
|
||||
dev = [
|
||||
"pytest>=7.0.0",
|
||||
"pytest-cov>=4.0.0",
|
||||
"black>=22.0.0",
|
||||
"flake8>=5.0.0",
|
||||
"pyright>=1.1.0",
|
||||
"yamllint>=1.28.0",
|
||||
"pre-commit>=3.0.0",
|
||||
]
|
||||
|
||||
[project.scripts]
|
||||
laconic-so = "stack_orchestrator.main:cli"
|
||||
|
||||
[project.urls]
|
||||
Homepage = "https://git.vdb.to/cerc-io/stack-orchestrator"
|
||||
|
||||
[tool.setuptools.packages.find]
|
||||
where = ["."]
|
||||
|
||||
[tool.setuptools.package-data]
|
||||
"*" = ["data/**"]
|
||||
|
||||
[tool.black]
|
||||
line-length = 88
|
||||
target-version = ['py38']
|
||||
|
||||
[tool.flake8]
|
||||
max-line-length = 88
|
||||
extend-ignore = ["E203", "W503", "E402"]
|
||||
|
||||
[tool.pyright]
|
||||
pythonVersion = "3.9"
|
||||
typeCheckingMode = "basic"
|
||||
reportMissingImports = "none"
|
||||
reportMissingModuleSource = "none"
|
||||
reportUnusedImport = "error"
|
||||
include = ["stack_orchestrator/**/*.py", "tests/**/*.py"]
|
||||
exclude = ["**/build/**", "**/__pycache__/**"]
|
||||
|
||||
[tool.mypy]
|
||||
python_version = "3.8"
|
||||
warn_return_any = true
|
||||
warn_unused_configs = true
|
||||
disallow_untyped_defs = true
|
||||
|
||||
[tool.pytest.ini_options]
|
||||
testpaths = ["tests"]
|
||||
python_files = ["test_*.py"]
|
||||
python_classes = ["Test*"]
|
||||
python_functions = ["test_*"]
|
||||
markers = [
|
||||
"slow: marks tests as slow (deselect with '-m \"not slow\"')",
|
||||
"e2e: marks tests as end-to-end (requires real infrastructure)",
|
||||
]
|
||||
addopts = [
|
||||
"--cov",
|
||||
"--cov-report=term-missing",
|
||||
"--cov-report=html",
|
||||
"--strict-markers",
|
||||
]
|
||||
asyncio_default_fixture_loop_scope = "function"
|
||||
|
||||
[tool.coverage.run]
|
||||
source = ["stack_orchestrator"]
|
||||
disable_warnings = ["couldnt-parse"]
|
||||
|
||||
[tool.coverage.report]
|
||||
exclude_lines = [
|
||||
"pragma: no cover",
|
||||
"def __repr__",
|
||||
"raise AssertionError",
|
||||
"raise NotImplementedError",
|
||||
]
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"pythonVersion": "3.9",
|
||||
"typeCheckingMode": "basic",
|
||||
"reportMissingImports": "none",
|
||||
"reportMissingModuleSource": "none",
|
||||
"reportUnusedImport": "error",
|
||||
"include": ["stack_orchestrator/**/*.py", "tests/**/*.py"],
|
||||
"exclude": ["**/build/**", "**/__pycache__/**"]
|
||||
}
|
||||
@@ -11,3 +11,5 @@ tomli==2.0.1
|
||||
validators==0.22.0
|
||||
kubernetes>=28.1.0
|
||||
humanfriendly>=10.0
|
||||
python-gnupg>=0.5.2
|
||||
requests>=2.3.2
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
# https://github.com/cerc-io/github-release-api
|
||||
# User must define: CERC_GH_RELEASE_SCRIPTS_DIR
|
||||
# pointing to the location of that cloned repository
|
||||
# e.g.
|
||||
# e.g.
|
||||
# cd ~/projects
|
||||
# git clone https://github.com/cerc-io/github-release-api
|
||||
# cd ./stack-orchestrator
|
||||
|
||||
@@ -94,7 +94,7 @@ sudo apt -y install jq
|
||||
# laconic-so depends on git
|
||||
sudo apt -y install git
|
||||
# curl used below
|
||||
sudo apt -y install curl
|
||||
sudo apt -y install curl
|
||||
# docker repo add depends on gnupg and updated ca-certificates
|
||||
sudo apt -y install ca-certificates gnupg
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
# Uses this script package to tag a new release:
|
||||
# User must define: CERC_GH_RELEASE_SCRIPTS_DIR
|
||||
# pointing to the location of that cloned repository
|
||||
# e.g.
|
||||
# e.g.
|
||||
# cd ~/projects
|
||||
# git clone https://github.com/cerc-io/github-release-api
|
||||
# cd ./stack-orchestrator
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
# See https://medium.com/nerd-for-tech/how-to-build-and-distribute-a-cli-tool-with-python-537ae41d9d78
|
||||
# See
|
||||
# https://medium.com/nerd-for-tech/how-to-build-and-distribute-a-cli-tool-with-python-537ae41d9d78
|
||||
from setuptools import setup, find_packages
|
||||
|
||||
with open("README.md", "r", encoding="utf-8") as fh:
|
||||
long_description = fh.read()
|
||||
with open("requirements.txt", "r", encoding="utf-8") as fh:
|
||||
@@ -7,26 +9,26 @@ with open("requirements.txt", "r", encoding="utf-8") as fh:
|
||||
with open("stack_orchestrator/data/version.txt", "r", encoding="utf-8") as fh:
|
||||
version = fh.readlines()[-1].strip(" \n")
|
||||
setup(
|
||||
name='laconic-stack-orchestrator',
|
||||
name="laconic-stack-orchestrator",
|
||||
version=version,
|
||||
author='Cerc',
|
||||
author_email='info@cerc.io',
|
||||
license='GNU Affero General Public License',
|
||||
description='Orchestrates deployment of the Laconic stack',
|
||||
author="Cerc",
|
||||
author_email="info@cerc.io",
|
||||
license="GNU Affero General Public License",
|
||||
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',
|
||||
py_modules=['stack_orchestrator'],
|
||||
url="https://git.vdb.to/cerc-io/stack-orchestrator",
|
||||
py_modules=["stack_orchestrator"],
|
||||
packages=find_packages(),
|
||||
install_requires=[requirements],
|
||||
python_requires='>=3.7',
|
||||
python_requires=">=3.7",
|
||||
include_package_data=True,
|
||||
package_data={'': ['data/**']},
|
||||
package_data={"": ["data/**"]},
|
||||
classifiers=[
|
||||
"Programming Language :: Python :: 3.8",
|
||||
"Operating System :: OS Independent",
|
||||
],
|
||||
entry_points={
|
||||
'console_scripts': ['laconic-so=stack_orchestrator.main:cli'],
|
||||
}
|
||||
"console_scripts": ["laconic-so=stack_orchestrator.main:cli"],
|
||||
},
|
||||
)
|
||||
|
||||
+30
-11
@@ -23,11 +23,10 @@ def get_stack(config, stack):
|
||||
if stack == "package-registry":
|
||||
return package_registry_stack(config, stack)
|
||||
else:
|
||||
return base_stack(config, stack)
|
||||
return default_stack(config, stack)
|
||||
|
||||
|
||||
class base_stack(ABC):
|
||||
|
||||
def __init__(self, config, stack):
|
||||
self.config = config
|
||||
self.stack = stack
|
||||
@@ -41,15 +40,27 @@ class base_stack(ABC):
|
||||
pass
|
||||
|
||||
|
||||
class package_registry_stack(base_stack):
|
||||
class default_stack(base_stack):
|
||||
"""Default stack implementation for stacks without specific handling."""
|
||||
|
||||
def ensure_available(self):
|
||||
return True
|
||||
|
||||
def get_url(self):
|
||||
return None
|
||||
|
||||
|
||||
class package_registry_stack(base_stack):
|
||||
def ensure_available(self):
|
||||
self.url = "<no registry url set>"
|
||||
# Check if we were given an external registry URL
|
||||
url_from_environment = os.environ.get("CERC_NPM_REGISTRY_URL")
|
||||
if url_from_environment:
|
||||
if self.config.verbose:
|
||||
print(f"Using package registry url from CERC_NPM_REGISTRY_URL: {url_from_environment}")
|
||||
print(
|
||||
f"Using package registry url from CERC_NPM_REGISTRY_URL: "
|
||||
f"{url_from_environment}"
|
||||
)
|
||||
self.url = url_from_environment
|
||||
else:
|
||||
# Otherwise we expect to use the local package-registry stack
|
||||
@@ -62,10 +73,16 @@ class package_registry_stack(base_stack):
|
||||
# TODO: get url from deploy-stack
|
||||
self.url = "http://gitea.local:3000/api/packages/cerc-io/npm/"
|
||||
else:
|
||||
# If not, print a message about how to start it and return fail to the caller
|
||||
print("ERROR: The package-registry stack is not running, and no external registry "
|
||||
"specified with CERC_NPM_REGISTRY_URL")
|
||||
print("ERROR: Start the local package registry with: laconic-so --stack package-registry deploy-system up")
|
||||
# If not, print a message about how to start it and return fail to the
|
||||
# caller
|
||||
print(
|
||||
"ERROR: The package-registry stack is not running, "
|
||||
"and no external registry specified with CERC_NPM_REGISTRY_URL"
|
||||
)
|
||||
print(
|
||||
"ERROR: Start the local package registry with: "
|
||||
"laconic-so --stack package-registry deploy-system up"
|
||||
)
|
||||
return False
|
||||
return True
|
||||
|
||||
@@ -76,7 +93,9 @@ class package_registry_stack(base_stack):
|
||||
def get_npm_registry_url():
|
||||
# If an auth token is not defined, we assume the default should be the cerc registry
|
||||
# If an auth token is defined, we assume the local gitea should be used.
|
||||
default_npm_registry_url = "http://gitea.local:3000/api/packages/cerc-io/npm/" if config(
|
||||
"CERC_NPM_AUTH_TOKEN", default=None
|
||||
) else "https://git.vdb.to/api/packages/cerc-io/npm/"
|
||||
default_npm_registry_url = (
|
||||
"http://gitea.local:3000/api/packages/cerc-io/npm/"
|
||||
if config("CERC_NPM_AUTH_TOKEN", default=None)
|
||||
else "https://git.vdb.to/api/packages/cerc-io/npm/"
|
||||
)
|
||||
return config("CERC_NPM_REGISTRY_URL", default=default_npm_registry_url)
|
||||
|
||||
@@ -18,7 +18,8 @@
|
||||
# env vars:
|
||||
# CERC_REPO_BASE_DIR defaults to ~/cerc
|
||||
|
||||
# TODO: display the available list of containers; allow re-build of either all or specific containers
|
||||
# TODO: display the available list of containers;
|
||||
# allow re-build of either all or specific containers
|
||||
|
||||
import os
|
||||
import sys
|
||||
@@ -34,14 +35,17 @@ from stack_orchestrator.build.publish import publish_image
|
||||
from stack_orchestrator.build.build_util import get_containers_in_scope
|
||||
|
||||
# TODO: find a place for this
|
||||
# epilog="Config provided either in .env or settings.ini or env vars: CERC_REPO_BASE_DIR (defaults to ~/cerc)"
|
||||
# epilog="Config provided either in .env or settings.ini or env vars:
|
||||
# CERC_REPO_BASE_DIR (defaults to ~/cerc)"
|
||||
|
||||
|
||||
def make_container_build_env(dev_root_path: str,
|
||||
container_build_dir: str,
|
||||
debug: bool,
|
||||
force_rebuild: bool,
|
||||
extra_build_args: str):
|
||||
def make_container_build_env(
|
||||
dev_root_path: str,
|
||||
container_build_dir: str,
|
||||
debug: bool,
|
||||
force_rebuild: bool,
|
||||
extra_build_args: str,
|
||||
):
|
||||
container_build_env = {
|
||||
"CERC_NPM_REGISTRY_URL": get_npm_registry_url(),
|
||||
"CERC_GO_AUTH_TOKEN": config("CERC_GO_AUTH_TOKEN", default=""),
|
||||
@@ -50,11 +54,15 @@ def make_container_build_env(dev_root_path: str,
|
||||
"CERC_CONTAINER_BASE_DIR": container_build_dir,
|
||||
"CERC_HOST_UID": f"{os.getuid()}",
|
||||
"CERC_HOST_GID": f"{os.getgid()}",
|
||||
"DOCKER_BUILDKIT": config("DOCKER_BUILDKIT", default="0")
|
||||
"DOCKER_BUILDKIT": config("DOCKER_BUILDKIT", default="0"),
|
||||
}
|
||||
container_build_env.update({"CERC_SCRIPT_DEBUG": "true"} if debug else {})
|
||||
container_build_env.update({"CERC_FORCE_REBUILD": "true"} if force_rebuild else {})
|
||||
container_build_env.update({"CERC_CONTAINER_EXTRA_BUILD_ARGS": extra_build_args} if extra_build_args else {})
|
||||
container_build_env.update(
|
||||
{"CERC_CONTAINER_EXTRA_BUILD_ARGS": extra_build_args}
|
||||
if extra_build_args
|
||||
else {}
|
||||
)
|
||||
docker_host_env = os.getenv("DOCKER_HOST")
|
||||
if docker_host_env:
|
||||
container_build_env.update({"DOCKER_HOST": docker_host_env})
|
||||
@@ -67,12 +75,18 @@ def process_container(build_context: BuildContext) -> bool:
|
||||
print(f"Building: {build_context.container}")
|
||||
|
||||
default_container_tag = f"{build_context.container}:local"
|
||||
build_context.container_build_env.update({"CERC_DEFAULT_CONTAINER_IMAGE_TAG": default_container_tag})
|
||||
build_context.container_build_env.update(
|
||||
{"CERC_DEFAULT_CONTAINER_IMAGE_TAG": default_container_tag}
|
||||
)
|
||||
|
||||
# Check if this is in an external stack
|
||||
if stack_is_external(build_context.stack):
|
||||
container_parent_dir = Path(build_context.stack).parent.parent.joinpath("container-build")
|
||||
temp_build_dir = container_parent_dir.joinpath(build_context.container.replace("/", "-"))
|
||||
container_parent_dir = Path(build_context.stack).parent.parent.joinpath(
|
||||
"container-build"
|
||||
)
|
||||
temp_build_dir = container_parent_dir.joinpath(
|
||||
build_context.container.replace("/", "-")
|
||||
)
|
||||
temp_build_script_filename = temp_build_dir.joinpath("build.sh")
|
||||
# Now check if the container exists in the external stack.
|
||||
if not temp_build_script_filename.exists():
|
||||
@@ -90,21 +104,34 @@ def process_container(build_context: BuildContext) -> bool:
|
||||
build_command = build_script_filename.as_posix()
|
||||
else:
|
||||
if opts.o.verbose:
|
||||
print(f"No script file found: {build_script_filename}, using default build script")
|
||||
repo_dir = build_context.container.split('/')[1]
|
||||
# TODO: make this less of a hack -- should be specified in some metadata somewhere
|
||||
# Check if we have a repo for this container. If not, set the context dir to the container-build subdir
|
||||
print(
|
||||
f"No script file found: {build_script_filename}, "
|
||||
"using default build script"
|
||||
)
|
||||
repo_dir = build_context.container.split("/")[1]
|
||||
# TODO: make this less of a hack -- should be specified in
|
||||
# some metadata somewhere. Check if we have a repo for this
|
||||
# container. If not, set the context dir to container-build subdir
|
||||
repo_full_path = os.path.join(build_context.dev_root_path, repo_dir)
|
||||
repo_dir_or_build_dir = repo_full_path if os.path.exists(repo_full_path) else build_dir
|
||||
build_command = os.path.join(build_context.container_build_dir,
|
||||
"default-build.sh") + f" {default_container_tag} {repo_dir_or_build_dir}"
|
||||
repo_dir_or_build_dir = (
|
||||
repo_full_path if os.path.exists(repo_full_path) else build_dir
|
||||
)
|
||||
build_command = (
|
||||
os.path.join(build_context.container_build_dir, "default-build.sh")
|
||||
+ f" {default_container_tag} {repo_dir_or_build_dir}"
|
||||
)
|
||||
if not opts.o.dry_run:
|
||||
# No PATH at all causes failures with podman.
|
||||
if "PATH" not in build_context.container_build_env:
|
||||
build_context.container_build_env["PATH"] = os.environ["PATH"]
|
||||
if opts.o.verbose:
|
||||
print(f"Executing: {build_command} with environment: {build_context.container_build_env}")
|
||||
build_result = subprocess.run(build_command, shell=True, env=build_context.container_build_env)
|
||||
print(
|
||||
f"Executing: {build_command} with environment: "
|
||||
f"{build_context.container_build_env}"
|
||||
)
|
||||
build_result = subprocess.run(
|
||||
build_command, shell=True, env=build_context.container_build_env
|
||||
)
|
||||
if opts.o.verbose:
|
||||
print(f"Return code is: {build_result.returncode}")
|
||||
if build_result.returncode != 0:
|
||||
@@ -117,33 +144,61 @@ def process_container(build_context: BuildContext) -> bool:
|
||||
|
||||
|
||||
@click.command()
|
||||
@click.option('--include', help="only build these containers")
|
||||
@click.option('--exclude', help="don\'t build these containers")
|
||||
@click.option("--force-rebuild", is_flag=True, default=False, help="Override dependency checking -- always rebuild")
|
||||
@click.option("--include", help="only build these containers")
|
||||
@click.option("--exclude", help="don't build these containers")
|
||||
@click.option(
|
||||
"--force-rebuild",
|
||||
is_flag=True,
|
||||
default=False,
|
||||
help="Override dependency checking -- always rebuild",
|
||||
)
|
||||
@click.option("--extra-build-args", help="Supply extra arguments to build")
|
||||
@click.option("--publish-images", is_flag=True, default=False, help="Publish the built images in the specified image registry")
|
||||
@click.option("--image-registry", help="Specify the image registry for --publish-images")
|
||||
@click.option(
|
||||
"--publish-images",
|
||||
is_flag=True,
|
||||
default=False,
|
||||
help="Publish the built images in the specified image registry",
|
||||
)
|
||||
@click.option(
|
||||
"--image-registry", help="Specify the image registry for --publish-images"
|
||||
)
|
||||
@click.pass_context
|
||||
def command(ctx, include, exclude, force_rebuild, extra_build_args, publish_images, image_registry):
|
||||
'''build the set of containers required for a complete stack'''
|
||||
def command(
|
||||
ctx,
|
||||
include,
|
||||
exclude,
|
||||
force_rebuild,
|
||||
extra_build_args,
|
||||
publish_images,
|
||||
image_registry,
|
||||
):
|
||||
"""build the set of containers required for a complete stack"""
|
||||
|
||||
local_stack = ctx.obj.local_stack
|
||||
stack = ctx.obj.stack
|
||||
|
||||
# See: https://stackoverflow.com/questions/25389095/python-get-path-of-root-project-structure
|
||||
container_build_dir = Path(__file__).absolute().parent.parent.joinpath("data", "container-build")
|
||||
# See: https://stackoverflow.com/questions/25389095/
|
||||
# python-get-path-of-root-project-structure
|
||||
container_build_dir = (
|
||||
Path(__file__).absolute().parent.parent.joinpath("data", "container-build")
|
||||
)
|
||||
|
||||
if local_stack:
|
||||
dev_root_path = os.getcwd()[0:os.getcwd().rindex("stack-orchestrator")]
|
||||
print(f'Local stack dev_root_path (CERC_REPO_BASE_DIR) overridden to: {dev_root_path}')
|
||||
dev_root_path = os.getcwd()[0 : os.getcwd().rindex("stack-orchestrator")]
|
||||
print(
|
||||
f"Local stack dev_root_path (CERC_REPO_BASE_DIR) overridden to: "
|
||||
f"{dev_root_path}"
|
||||
)
|
||||
else:
|
||||
dev_root_path = os.path.expanduser(config("CERC_REPO_BASE_DIR", default="~/cerc"))
|
||||
dev_root_path = os.path.expanduser(
|
||||
config("CERC_REPO_BASE_DIR", default="~/cerc")
|
||||
)
|
||||
|
||||
if not opts.o.quiet:
|
||||
print(f'Dev Root is: {dev_root_path}')
|
||||
print(f"Dev Root is: {dev_root_path}")
|
||||
|
||||
if not os.path.isdir(dev_root_path):
|
||||
print('Dev root directory doesn\'t exist, creating')
|
||||
print("Dev root directory doesn't exist, creating")
|
||||
|
||||
if publish_images:
|
||||
if not image_registry:
|
||||
@@ -151,21 +206,22 @@ def command(ctx, include, exclude, force_rebuild, extra_build_args, publish_imag
|
||||
|
||||
containers_in_scope = get_containers_in_scope(stack)
|
||||
|
||||
container_build_env = make_container_build_env(dev_root_path,
|
||||
container_build_dir,
|
||||
opts.o.debug,
|
||||
force_rebuild,
|
||||
extra_build_args)
|
||||
container_build_env = make_container_build_env(
|
||||
dev_root_path,
|
||||
container_build_dir,
|
||||
opts.o.debug,
|
||||
force_rebuild,
|
||||
extra_build_args,
|
||||
)
|
||||
|
||||
for container in containers_in_scope:
|
||||
if include_exclude_check(container, include, exclude):
|
||||
|
||||
build_context = BuildContext(
|
||||
stack,
|
||||
container,
|
||||
container_build_dir,
|
||||
container_build_env,
|
||||
dev_root_path
|
||||
dev_root_path,
|
||||
)
|
||||
result = process_container(build_context)
|
||||
if result:
|
||||
@@ -174,10 +230,16 @@ def command(ctx, include, exclude, force_rebuild, extra_build_args, publish_imag
|
||||
else:
|
||||
print(f"Error running build for {build_context.container}")
|
||||
if not opts.o.continue_on_error:
|
||||
error_exit("container build failed and --continue-on-error not set, exiting")
|
||||
error_exit(
|
||||
"container build failed and --continue-on-error "
|
||||
"not set, exiting"
|
||||
)
|
||||
sys.exit(1)
|
||||
else:
|
||||
print("****** Container Build Error, continuing because --continue-on-error is set")
|
||||
print(
|
||||
"****** Container Build Error, continuing because "
|
||||
"--continue-on-error is set"
|
||||
)
|
||||
else:
|
||||
if opts.o.verbose:
|
||||
print(f"Excluding: {container}")
|
||||
|
||||
@@ -32,14 +32,18 @@ builder_js_image_name = "cerc/builder-js:local"
|
||||
|
||||
|
||||
@click.command()
|
||||
@click.option('--include', help="only build these packages")
|
||||
@click.option('--exclude', help="don\'t build these packages")
|
||||
@click.option("--force-rebuild", is_flag=True, default=False,
|
||||
help="Override existing target package version check -- force rebuild")
|
||||
@click.option("--include", help="only build these packages")
|
||||
@click.option("--exclude", help="don't build these packages")
|
||||
@click.option(
|
||||
"--force-rebuild",
|
||||
is_flag=True,
|
||||
default=False,
|
||||
help="Override existing target package version check -- force rebuild",
|
||||
)
|
||||
@click.option("--extra-build-args", help="Supply extra arguments to build")
|
||||
@click.pass_context
|
||||
def command(ctx, include, exclude, force_rebuild, extra_build_args):
|
||||
'''build the set of npm packages required for a complete stack'''
|
||||
"""build the set of npm packages required for a complete stack"""
|
||||
|
||||
quiet = ctx.obj.quiet
|
||||
verbose = ctx.obj.verbose
|
||||
@@ -65,45 +69,54 @@ def command(ctx, include, exclude, force_rebuild, extra_build_args):
|
||||
sys.exit(1)
|
||||
|
||||
if local_stack:
|
||||
dev_root_path = os.getcwd()[0:os.getcwd().rindex("stack-orchestrator")]
|
||||
print(f'Local stack dev_root_path (CERC_REPO_BASE_DIR) overridden to: {dev_root_path}')
|
||||
dev_root_path = os.getcwd()[0 : os.getcwd().rindex("stack-orchestrator")]
|
||||
print(
|
||||
f"Local stack dev_root_path (CERC_REPO_BASE_DIR) overridden to: "
|
||||
f"{dev_root_path}"
|
||||
)
|
||||
else:
|
||||
dev_root_path = os.path.expanduser(config("CERC_REPO_BASE_DIR", default="~/cerc"))
|
||||
dev_root_path = os.path.expanduser(
|
||||
config("CERC_REPO_BASE_DIR", default="~/cerc")
|
||||
)
|
||||
|
||||
build_root_path = os.path.join(dev_root_path, "build-trees")
|
||||
|
||||
if verbose:
|
||||
print(f'Dev Root is: {dev_root_path}')
|
||||
print(f"Dev Root is: {dev_root_path}")
|
||||
|
||||
if not os.path.isdir(dev_root_path):
|
||||
print('Dev root directory doesn\'t exist, creating')
|
||||
print("Dev root directory doesn't exist, creating")
|
||||
os.makedirs(dev_root_path)
|
||||
if not os.path.isdir(dev_root_path):
|
||||
print('Build root directory doesn\'t exist, creating')
|
||||
print("Build root directory doesn't exist, creating")
|
||||
os.makedirs(build_root_path)
|
||||
|
||||
# See: https://stackoverflow.com/a/20885799/1701505
|
||||
from stack_orchestrator 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:
|
||||
all_packages = package_list_file.read().splitlines()
|
||||
|
||||
packages_in_scope = []
|
||||
if stack:
|
||||
stack_config = get_parsed_stack_config(stack)
|
||||
# TODO: syntax check the input here
|
||||
packages_in_scope = stack_config['npms']
|
||||
packages_in_scope = stack_config["npms"]
|
||||
else:
|
||||
packages_in_scope = all_packages
|
||||
|
||||
if verbose:
|
||||
print(f'Packages: {packages_in_scope}')
|
||||
print(f"Packages: {packages_in_scope}")
|
||||
|
||||
def build_package(package):
|
||||
if not quiet:
|
||||
print(f"Building npm package: {package}")
|
||||
repo_dir = package
|
||||
repo_full_path = os.path.join(dev_root_path, repo_dir)
|
||||
# Copy the repo and build that to avoid propagating JS tooling file changes back into the cloned repo
|
||||
# Copy the repo and build that to avoid propagating
|
||||
# JS tooling file changes back into the cloned repo
|
||||
repo_copy_path = os.path.join(build_root_path, repo_dir)
|
||||
# First delete any old build tree
|
||||
if os.path.isdir(repo_copy_path):
|
||||
@@ -116,41 +129,63 @@ def command(ctx, include, exclude, force_rebuild, extra_build_args):
|
||||
print(f"Copying build tree from: {repo_full_path} to: {repo_copy_path}")
|
||||
if not dry_run:
|
||||
copytree(repo_full_path, repo_copy_path)
|
||||
build_command = ["sh", "-c", f"cd /workspace && build-npm-package-local-dependencies.sh {npm_registry_url}"]
|
||||
build_command = [
|
||||
"sh",
|
||||
"-c",
|
||||
"cd /workspace && "
|
||||
f"build-npm-package-local-dependencies.sh {npm_registry_url}",
|
||||
]
|
||||
if not dry_run:
|
||||
if verbose:
|
||||
print(f"Executing: {build_command}")
|
||||
# Originally we used the PEP 584 merge operator:
|
||||
# envs = {"CERC_NPM_AUTH_TOKEN": npm_registry_url_token} | ({"CERC_SCRIPT_DEBUG": "true"} if debug else {})
|
||||
# but that isn't available in Python 3.8 (default in Ubuntu 20) so for now we use dict.update:
|
||||
envs = {"CERC_NPM_AUTH_TOKEN": npm_registry_url_token,
|
||||
"LACONIC_HOSTED_CONFIG_FILE": "config-hosted.yml" # Convention used by our web app packages
|
||||
}
|
||||
# envs = {"CERC_NPM_AUTH_TOKEN": npm_registry_url_token} |
|
||||
# ({"CERC_SCRIPT_DEBUG": "true"} if debug else {})
|
||||
# but that isn't available in Python 3.8 (default in Ubuntu 20)
|
||||
# so for now we use dict.update:
|
||||
envs = {
|
||||
"CERC_NPM_AUTH_TOKEN": npm_registry_url_token,
|
||||
# Convention used by our web app packages
|
||||
"LACONIC_HOSTED_CONFIG_FILE": "config-hosted.yml",
|
||||
}
|
||||
envs.update({"CERC_SCRIPT_DEBUG": "true"} if debug else {})
|
||||
envs.update({"CERC_FORCE_REBUILD": "true"} if force_rebuild else {})
|
||||
envs.update({"CERC_CONTAINER_EXTRA_BUILD_ARGS": extra_build_args} if extra_build_args else {})
|
||||
envs.update(
|
||||
{"CERC_CONTAINER_EXTRA_BUILD_ARGS": extra_build_args}
|
||||
if extra_build_args
|
||||
else {}
|
||||
)
|
||||
try:
|
||||
docker.run(builder_js_image_name,
|
||||
remove=True,
|
||||
interactive=True,
|
||||
tty=True,
|
||||
user=f"{os.getuid()}:{os.getgid()}",
|
||||
envs=envs,
|
||||
# TODO: detect this host name in npm_registry_url rather than hard-wiring it
|
||||
add_hosts=[("gitea.local", "host-gateway")],
|
||||
volumes=[(repo_copy_path, "/workspace")],
|
||||
command=build_command
|
||||
)
|
||||
# Note that although the docs say that build_result should contain
|
||||
# the command output as a string, in reality it is always the empty string.
|
||||
# Since we detect errors via catching exceptions below, we can safely ignore it here.
|
||||
docker.run(
|
||||
builder_js_image_name,
|
||||
remove=True,
|
||||
interactive=True,
|
||||
tty=True,
|
||||
user=f"{os.getuid()}:{os.getgid()}",
|
||||
envs=envs,
|
||||
# TODO: detect this host name in npm_registry_url
|
||||
# rather than hard-wiring it
|
||||
add_hosts=[("gitea.local", "host-gateway")],
|
||||
volumes=[(repo_copy_path, "/workspace")],
|
||||
command=build_command,
|
||||
)
|
||||
# Note that although the docs say that build_result should
|
||||
# contain the command output as a string, in reality it is
|
||||
# always the empty string. Since we detect errors via catching
|
||||
# exceptions below, we can safely ignore it here.
|
||||
except DockerException as e:
|
||||
print(f"Error executing build for {package} in container:\n {e}")
|
||||
if not continue_on_error:
|
||||
print("FATAL Error: build failed and --continue-on-error not set, exiting")
|
||||
print(
|
||||
"FATAL Error: build failed and --continue-on-error "
|
||||
"not set, exiting"
|
||||
)
|
||||
sys.exit(1)
|
||||
else:
|
||||
print("****** Build Error, continuing because --continue-on-error is set")
|
||||
print(
|
||||
"****** Build Error, continuing because "
|
||||
"--continue-on-error is set"
|
||||
)
|
||||
|
||||
else:
|
||||
print("Skipped")
|
||||
@@ -168,6 +203,12 @@ def _ensure_prerequisites():
|
||||
# Tell the user how to build it if not
|
||||
images = docker.image.list(builder_js_image_name)
|
||||
if len(images) == 0:
|
||||
print(f"FATAL: builder image: {builder_js_image_name} is required but was not found")
|
||||
print("Please run this command to create it: laconic-so --stack build-support build-containers")
|
||||
print(
|
||||
f"FATAL: builder image: {builder_js_image_name} is required "
|
||||
"but was not found"
|
||||
)
|
||||
print(
|
||||
"Please run this command to create it: "
|
||||
"laconic-so --stack build-support build-containers"
|
||||
)
|
||||
sys.exit(1)
|
||||
|
||||
@@ -24,6 +24,5 @@ class BuildContext:
|
||||
stack: str
|
||||
container: str
|
||||
container_build_dir: Path
|
||||
container_build_env: Mapping[str,str]
|
||||
container_build_env: Mapping[str, str]
|
||||
dev_root_path: str
|
||||
|
||||
|
||||
@@ -20,21 +20,23 @@ from stack_orchestrator.util import get_parsed_stack_config, warn_exit
|
||||
|
||||
|
||||
def get_containers_in_scope(stack: str):
|
||||
|
||||
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']
|
||||
containers_in_scope = stack_config["containers"]
|
||||
else:
|
||||
# See: https://stackoverflow.com/a/20885799/1701505
|
||||
from stack_orchestrator 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_in_scope = container_list_file.read().splitlines()
|
||||
|
||||
if opts.o.verbose:
|
||||
print(f'Containers: {containers_in_scope}')
|
||||
print(f"Containers: {containers_in_scope}")
|
||||
if stack:
|
||||
print(f"Stack: {stack}")
|
||||
|
||||
|
||||
@@ -18,7 +18,8 @@
|
||||
# env vars:
|
||||
# CERC_REPO_BASE_DIR defaults to ~/cerc
|
||||
|
||||
# TODO: display the available list of containers; allow re-build of either all or specific containers
|
||||
# TODO: display the available list of containers;
|
||||
# allow re-build of either all or specific containers
|
||||
|
||||
import os
|
||||
import sys
|
||||
@@ -32,40 +33,55 @@ from stack_orchestrator.build.build_types import BuildContext
|
||||
|
||||
|
||||
@click.command()
|
||||
@click.option('--base-container')
|
||||
@click.option('--source-repo', help="directory containing the webapp to build", required=True)
|
||||
@click.option("--force-rebuild", is_flag=True, default=False, help="Override dependency checking -- always rebuild")
|
||||
@click.option("--base-container")
|
||||
@click.option(
|
||||
"--source-repo", help="directory containing the webapp to build", required=True
|
||||
)
|
||||
@click.option(
|
||||
"--force-rebuild",
|
||||
is_flag=True,
|
||||
default=False,
|
||||
help="Override dependency checking -- always rebuild",
|
||||
)
|
||||
@click.option("--extra-build-args", help="Supply extra arguments to build")
|
||||
@click.option("--tag", help="Container tag (default: cerc/<app_name>:local)")
|
||||
@click.pass_context
|
||||
def command(ctx, base_container, source_repo, force_rebuild, extra_build_args, tag):
|
||||
'''build the specified webapp container'''
|
||||
"""build the specified webapp container"""
|
||||
logger = TimedLogger()
|
||||
|
||||
quiet = ctx.obj.quiet
|
||||
debug = ctx.obj.debug
|
||||
verbose = ctx.obj.verbose
|
||||
local_stack = ctx.obj.local_stack
|
||||
stack = ctx.obj.stack
|
||||
|
||||
# See: https://stackoverflow.com/questions/25389095/python-get-path-of-root-project-structure
|
||||
container_build_dir = Path(__file__).absolute().parent.parent.joinpath("data", "container-build")
|
||||
# See: https://stackoverflow.com/questions/25389095/
|
||||
# python-get-path-of-root-project-structure
|
||||
container_build_dir = (
|
||||
Path(__file__).absolute().parent.parent.joinpath("data", "container-build")
|
||||
)
|
||||
|
||||
if local_stack:
|
||||
dev_root_path = os.getcwd()[0:os.getcwd().rindex("stack-orchestrator")]
|
||||
logger.log(f'Local stack dev_root_path (CERC_REPO_BASE_DIR) overridden to: {dev_root_path}')
|
||||
dev_root_path = os.getcwd()[0 : os.getcwd().rindex("stack-orchestrator")]
|
||||
logger.log(
|
||||
f"Local stack dev_root_path (CERC_REPO_BASE_DIR) overridden to: "
|
||||
f"{dev_root_path}"
|
||||
)
|
||||
else:
|
||||
dev_root_path = os.path.expanduser(config("CERC_REPO_BASE_DIR", default="~/cerc"))
|
||||
dev_root_path = os.path.expanduser(
|
||||
config("CERC_REPO_BASE_DIR", default="~/cerc")
|
||||
)
|
||||
|
||||
if verbose:
|
||||
logger.log(f'Dev Root is: {dev_root_path}')
|
||||
logger.log(f"Dev Root is: {dev_root_path}")
|
||||
|
||||
if not base_container:
|
||||
base_container = determine_base_container(source_repo)
|
||||
|
||||
# First build the base container.
|
||||
container_build_env = build_containers.make_container_build_env(dev_root_path, container_build_dir, debug,
|
||||
force_rebuild, extra_build_args)
|
||||
container_build_env = build_containers.make_container_build_env(
|
||||
dev_root_path, container_build_dir, debug, force_rebuild, extra_build_args
|
||||
)
|
||||
|
||||
if verbose:
|
||||
logger.log(f"Building base container: {base_container}")
|
||||
@@ -85,12 +101,13 @@ def command(ctx, base_container, source_repo, force_rebuild, extra_build_args, t
|
||||
if verbose:
|
||||
logger.log(f"Base container {base_container} build finished.")
|
||||
|
||||
# Now build the target webapp. We use the same build script, but with a different Dockerfile and work dir.
|
||||
# Now build the target webapp. We use the same build script,
|
||||
# but with a different Dockerfile and work dir.
|
||||
container_build_env["CERC_WEBAPP_BUILD_RUNNING"] = "true"
|
||||
container_build_env["CERC_CONTAINER_BUILD_WORK_DIR"] = os.path.abspath(source_repo)
|
||||
container_build_env["CERC_CONTAINER_BUILD_DOCKERFILE"] = os.path.join(container_build_dir,
|
||||
base_container.replace("/", "-"),
|
||||
"Dockerfile.webapp")
|
||||
container_build_env["CERC_CONTAINER_BUILD_DOCKERFILE"] = os.path.join(
|
||||
container_build_dir, base_container.replace("/", "-"), "Dockerfile.webapp"
|
||||
)
|
||||
if not tag:
|
||||
webapp_name = os.path.abspath(source_repo).split(os.path.sep)[-1]
|
||||
tag = f"cerc/{webapp_name}:local"
|
||||
|
||||
@@ -52,7 +52,8 @@ def _local_tag_for(container: str):
|
||||
|
||||
# See: https://docker-docs.uclv.cu/registry/spec/api/
|
||||
# Emulate this:
|
||||
# $ curl -u "my-username:my-token" -X GET "https://<container-registry-hostname>/v2/cerc-io/cerc/test-container/tags/list"
|
||||
# $ curl -u "my-username:my-token" -X GET \
|
||||
# "https://<container-registry-hostname>/v2/cerc-io/cerc/test-container/tags/list"
|
||||
# {"name":"cerc-io/cerc/test-container","tags":["202402232130","202402232208"]}
|
||||
def _get_tags_for_container(container: str, registry_info: RegistryInfo) -> List[str]:
|
||||
# registry looks like: git.vdb.to/cerc-io
|
||||
@@ -60,7 +61,9 @@ def _get_tags_for_container(container: str, registry_info: RegistryInfo) -> List
|
||||
url = f"https://{registry_parts[0]}/v2/{registry_parts[1]}/{container}/tags/list"
|
||||
if opts.o.debug:
|
||||
print(f"Fetching tags from: {url}")
|
||||
response = requests.get(url, auth=(registry_info.registry_username, registry_info.registry_token))
|
||||
response = requests.get(
|
||||
url, auth=(registry_info.registry_username, registry_info.registry_token)
|
||||
)
|
||||
if response.status_code == 200:
|
||||
tag_info = response.json()
|
||||
if opts.o.debug:
|
||||
@@ -68,7 +71,10 @@ def _get_tags_for_container(container: str, registry_info: RegistryInfo) -> List
|
||||
tags_array = tag_info["tags"]
|
||||
return tags_array
|
||||
else:
|
||||
error_exit(f"failed to fetch tags from image registry, status code: {response.status_code}")
|
||||
error_exit(
|
||||
f"failed to fetch tags from image registry, "
|
||||
f"status code: {response.status_code}"
|
||||
)
|
||||
|
||||
|
||||
def _find_latest(candidate_tags: List[str]):
|
||||
@@ -79,9 +85,9 @@ def _find_latest(candidate_tags: List[str]):
|
||||
return sorted_candidates[-1]
|
||||
|
||||
|
||||
def _filter_for_platform(container: str,
|
||||
registry_info: RegistryInfo,
|
||||
tag_list: List[str]) -> List[str] :
|
||||
def _filter_for_platform(
|
||||
container: str, registry_info: RegistryInfo, tag_list: List[str]
|
||||
) -> List[str]:
|
||||
filtered_tags = []
|
||||
this_machine = platform.machine()
|
||||
# Translate between Python and docker platform names
|
||||
@@ -98,7 +104,7 @@ def _filter_for_platform(container: str,
|
||||
manifest = manifest_cmd.inspect_verbose(remote_tag)
|
||||
if opts.o.debug:
|
||||
print(f"manifest: {manifest}")
|
||||
image_architecture = manifest["Descriptor"]["platform"]["architecture"]
|
||||
image_architecture = manifest["Descriptor"]["platform"]["architecture"]
|
||||
if opts.o.debug:
|
||||
print(f"image_architecture: {image_architecture}")
|
||||
if this_machine == image_architecture:
|
||||
@@ -137,21 +143,44 @@ def _add_local_tag(remote_tag: str, registry: str, local_tag: str):
|
||||
|
||||
|
||||
@click.command()
|
||||
@click.option('--include', help="only fetch these containers")
|
||||
@click.option('--exclude', help="don\'t fetch these containers")
|
||||
@click.option("--force-local-overwrite", is_flag=True, default=False, help="Overwrite a locally built image, if present")
|
||||
@click.option("--image-registry", required=True, help="Specify the image registry to fetch from")
|
||||
@click.option("--registry-username", required=True, help="Specify the image registry username")
|
||||
@click.option("--registry-token", required=True, help="Specify the image registry access token")
|
||||
@click.option("--include", help="only fetch these containers")
|
||||
@click.option("--exclude", help="don't fetch these containers")
|
||||
@click.option(
|
||||
"--force-local-overwrite",
|
||||
is_flag=True,
|
||||
default=False,
|
||||
help="Overwrite a locally built image, if present",
|
||||
)
|
||||
@click.option(
|
||||
"--image-registry", required=True, help="Specify the image registry to fetch from"
|
||||
)
|
||||
@click.option(
|
||||
"--registry-username", required=True, help="Specify the image registry username"
|
||||
)
|
||||
@click.option(
|
||||
"--registry-token", required=True, help="Specify the image registry access token"
|
||||
)
|
||||
@click.pass_context
|
||||
def command(ctx, include, exclude, force_local_overwrite, image_registry, registry_username, registry_token):
|
||||
'''EXPERIMENTAL: fetch the images for a stack from remote registry'''
|
||||
def command(
|
||||
ctx,
|
||||
include,
|
||||
exclude,
|
||||
force_local_overwrite,
|
||||
image_registry,
|
||||
registry_username,
|
||||
registry_token,
|
||||
):
|
||||
"""EXPERIMENTAL: fetch the images for a stack from remote registry"""
|
||||
|
||||
registry_info = RegistryInfo(image_registry, registry_username, registry_token)
|
||||
docker = DockerClient()
|
||||
if not opts.o.quiet:
|
||||
print("Logging into container registry:")
|
||||
docker.login(registry_info.registry, registry_info.registry_username, registry_info.registry_token)
|
||||
docker.login(
|
||||
registry_info.registry,
|
||||
registry_info.registry_username,
|
||||
registry_info.registry_token,
|
||||
)
|
||||
# Generate list of target containers
|
||||
stack = ctx.obj.stack
|
||||
containers_in_scope = get_containers_in_scope(stack)
|
||||
@@ -172,19 +201,24 @@ def command(ctx, include, exclude, force_local_overwrite, image_registry, regist
|
||||
print(f"Fetching: {image_to_fetch}")
|
||||
_fetch_image(image_to_fetch, registry_info)
|
||||
# Now check if the target container already exists exists locally already
|
||||
if (_exists_locally(container)):
|
||||
if _exists_locally(container):
|
||||
if not opts.o.quiet:
|
||||
print(f"Container image {container} already exists locally")
|
||||
# if so, fail unless the user specified force-local-overwrite
|
||||
if (force_local_overwrite):
|
||||
if force_local_overwrite:
|
||||
# In that case remove the existing :local tag
|
||||
if not opts.o.quiet:
|
||||
print(f"Warning: overwriting local tag from this image: {container} because "
|
||||
"--force-local-overwrite was specified")
|
||||
print(
|
||||
f"Warning: overwriting local tag from this image: "
|
||||
f"{container} because --force-local-overwrite was specified"
|
||||
)
|
||||
else:
|
||||
if not opts.o.quiet:
|
||||
print(f"Skipping local tagging for this image: {container} because that would "
|
||||
"overwrite an existing :local tagged image, use --force-local-overwrite to do so.")
|
||||
print(
|
||||
f"Skipping local tagging for this image: {container} "
|
||||
"because that would overwrite an existing :local tagged "
|
||||
"image, use --force-local-overwrite to do so."
|
||||
)
|
||||
continue
|
||||
# Tag the fetched image with the :local tag
|
||||
_add_local_tag(image_to_fetch, image_registry, local_tag)
|
||||
@@ -192,4 +226,7 @@ def command(ctx, include, exclude, force_local_overwrite, image_registry, regist
|
||||
if opts.o.verbose:
|
||||
print(f"Excluding: {container}")
|
||||
if not all_containers_found:
|
||||
print("Warning: couldn't find usable images for one or more containers, this stack will not deploy")
|
||||
print(
|
||||
"Warning: couldn't find usable images for one or more containers, "
|
||||
"this stack will not deploy"
|
||||
)
|
||||
|
||||
@@ -34,5 +34,13 @@ volumes_key = "volumes"
|
||||
security_key = "security"
|
||||
annotations_key = "annotations"
|
||||
labels_key = "labels"
|
||||
replicas_key = "replicas"
|
||||
node_affinities_key = "node-affinities"
|
||||
node_tolerations_key = "node-tolerations"
|
||||
kind_config_filename = "kind-config.yml"
|
||||
kube_config_filename = "kubeconfig.yml"
|
||||
cri_base_filename = "cri-base.json"
|
||||
unlimited_memlock_key = "unlimited-memlock"
|
||||
runtime_class_key = "runtime-class"
|
||||
high_memlock_runtime = "high-memlock"
|
||||
high_memlock_spec_filename = "high-memlock-spec.json"
|
||||
|
||||
@@ -20,7 +20,7 @@ services:
|
||||
depends_on:
|
||||
generate-jwt:
|
||||
condition: service_completed_successfully
|
||||
env_file:
|
||||
env_file:
|
||||
- ../config/fixturenet-blast/${NETWORK:-fixturenet}.config
|
||||
blast-geth:
|
||||
image: blastio/blast-geth:${NETWORK:-testnet-sepolia}
|
||||
@@ -51,7 +51,7 @@ services:
|
||||
--nodiscover
|
||||
--maxpeers=0
|
||||
--rollup.disabletxpoolgossip=true
|
||||
env_file:
|
||||
env_file:
|
||||
- ../config/fixturenet-blast/${NETWORK:-fixturenet}.config
|
||||
depends_on:
|
||||
geth-init:
|
||||
@@ -73,7 +73,7 @@ services:
|
||||
--rollup.config="/blast/rollup.json"
|
||||
depends_on:
|
||||
- blast-geth
|
||||
env_file:
|
||||
env_file:
|
||||
- ../config/fixturenet-blast/${NETWORK:-fixturenet}.config
|
||||
|
||||
volumes:
|
||||
|
||||
@@ -14,4 +14,3 @@ services:
|
||||
- "9090"
|
||||
- "9091"
|
||||
- "1317"
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ services:
|
||||
depends_on:
|
||||
generate-jwt:
|
||||
condition: service_completed_successfully
|
||||
env_file:
|
||||
env_file:
|
||||
- ../config/mainnet-blast/${NETWORK:-mainnet}.config
|
||||
blast-geth:
|
||||
image: blastio/blast-geth:${NETWORK:-mainnet}
|
||||
@@ -53,7 +53,7 @@ services:
|
||||
--nodiscover
|
||||
--maxpeers=0
|
||||
--rollup.disabletxpoolgossip=true
|
||||
env_file:
|
||||
env_file:
|
||||
- ../config/mainnet-blast/${NETWORK:-mainnet}.config
|
||||
depends_on:
|
||||
geth-init:
|
||||
@@ -76,7 +76,7 @@ services:
|
||||
--rollup.config="/blast/rollup.json"
|
||||
depends_on:
|
||||
- blast-geth
|
||||
env_file:
|
||||
env_file:
|
||||
- ../config/mainnet-blast/${NETWORK:-mainnet}.config
|
||||
|
||||
volumes:
|
||||
|
||||
@@ -17,4 +17,3 @@ services:
|
||||
- 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
|
||||
|
||||
|
||||
@@ -32,4 +32,4 @@ services:
|
||||
volumes:
|
||||
reth_data:
|
||||
lighthouse_data:
|
||||
shared_data:
|
||||
shared_data:
|
||||
|
||||
@@ -12,7 +12,7 @@ services:
|
||||
POSTGRES_INITDB_ARGS: "-E UTF8 --locale=C"
|
||||
ports:
|
||||
- "5432"
|
||||
|
||||
|
||||
test-client:
|
||||
image: cerc/test-database-client:local
|
||||
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
GETH_ROLLUP_SEQUENCERHTTP=https://sequencer.s2.testblast.io
|
||||
OP_NODE_P2P_BOOTNODES=enr:-J-4QM3GLUFfKMSJQuP1UvuKQe8DyovE7Eaiit0l6By4zjTodkR4V8NWXJxNmlg8t8rP-Q-wp3jVmeAOml8cjMj__ROGAYznzb_HgmlkgnY0gmlwhA-cZ_eHb3BzdGFja4X947FQAIlzZWNwMjU2azGhAiuDqvB-AsVSRmnnWr6OHfjgY8YfNclFy9p02flKzXnOg3RjcIJ2YYN1ZHCCdmE,enr:-J-4QDCVpByqQ8nFqCS9aHicqwUfXgzFDslvpEyYz19lvkHLIdtcIGp2d4q5dxHdjRNTO6HXCsnIKxUeuZSPcEbyVQCGAYznzz0RgmlkgnY0gmlwhANiQfuHb3BzdGFja4X947FQAIlzZWNwMjU2azGhAy3AtF2Jh_aPdOohg506Hjmtx-fQ1AKmu71C7PfkWAw9g3RjcIJ2YYN1ZHCCdmE
|
||||
OP_NODE_P2P_BOOTNODES=enr:-J-4QM3GLUFfKMSJQuP1UvuKQe8DyovE7Eaiit0l6By4zjTodkR4V8NWXJxNmlg8t8rP-Q-wp3jVmeAOml8cjMj__ROGAYznzb_HgmlkgnY0gmlwhA-cZ_eHb3BzdGFja4X947FQAIlzZWNwMjU2azGhAiuDqvB-AsVSRmnnWr6OHfjgY8YfNclFy9p02flKzXnOg3RjcIJ2YYN1ZHCCdmE,enr:-J-4QDCVpByqQ8nFqCS9aHicqwUfXgzFDslvpEyYz19lvkHLIdtcIGp2d4q5dxHdjRNTO6HXCsnIKxUeuZSPcEbyVQCGAYznzz0RgmlkgnY0gmlwhANiQfuHb3BzdGFja4X947FQAIlzZWNwMjU2azGhAy3AtF2Jh_aPdOohg506Hjmtx-fQ1AKmu71C7PfkWAw9g3RjcIJ2YYN1ZHCCdmE
|
||||
|
||||
+1
-1
@@ -1411,4 +1411,4 @@
|
||||
"uid": "nT9VeZoVk",
|
||||
"version": 2,
|
||||
"weekStart": ""
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ MONIKER="localtestnet"
|
||||
KEYRING="test"
|
||||
KEYALGO="secp256k1"
|
||||
LOGLEVEL="${LOGLEVEL:-info}"
|
||||
DENOM="alnt"
|
||||
|
||||
|
||||
if [ "$1" == "clean" ] || [ ! -d "$HOME/.laconicd/data/blockstore.db" ]; then
|
||||
@@ -33,7 +34,7 @@ if [ "$1" == "clean" ] || [ ! -d "$HOME/.laconicd/data/blockstore.db" ]; then
|
||||
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 --default-denom photon
|
||||
laconicd init $MONIKER --chain-id $CHAINID --default-denom $DENOM
|
||||
|
||||
update_genesis() {
|
||||
jq "$1" $HOME/.laconicd/config/genesis.json > $HOME/.laconicd/config/tmp_genesis.json &&
|
||||
@@ -89,10 +90,12 @@ if [ "$1" == "clean" ] || [ ! -d "$HOME/.laconicd/data/blockstore.db" ]; then
|
||||
fi
|
||||
|
||||
# Allocate genesis accounts (cosmos formatted addresses)
|
||||
laconicd genesis add-genesis-account $KEY 100000000000000000000000000photon --keyring-backend $KEYRING
|
||||
# 10^30 alnt | 10^12 lnt
|
||||
laconicd genesis add-genesis-account $KEY 1000000000000000000000000000000$DENOM --keyring-backend $KEYRING
|
||||
|
||||
# Sign genesis transaction
|
||||
laconicd genesis gentx $KEY 1000000000000000000000photon --keyring-backend $KEYRING --chain-id $CHAINID
|
||||
# 10^24 alnt | 10^6 lnt
|
||||
laconicd genesis gentx $KEY 1000000000000000000000000$DENOM --keyring-backend $KEYRING --chain-id $CHAINID
|
||||
|
||||
# Collect genesis tx
|
||||
laconicd genesis collect-gentxs
|
||||
@@ -107,7 +110,7 @@ fi
|
||||
laconicd start \
|
||||
--pruning=nothing \
|
||||
--log_level $LOGLEVEL \
|
||||
--minimum-gas-prices=0.0001photon \
|
||||
--minimum-gas-prices=1$DENOM \
|
||||
--api.enable \
|
||||
--rpc.laddr="tcp://0.0.0.0:26657" \
|
||||
--gql-server --gql-playground
|
||||
|
||||
@@ -6,4 +6,4 @@ services:
|
||||
bondId:
|
||||
chainId: laconic_9000-1
|
||||
gas: 350000
|
||||
fees: 200000photon
|
||||
fees: 2000000alnt
|
||||
|
||||
+1
-1
@@ -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
|
||||
|
||||
@@ -56,7 +56,7 @@
|
||||
"value": "!validator-pubkey"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"supply": []
|
||||
},
|
||||
@@ -269,4 +269,4 @@
|
||||
"claims": null
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2084,4 +2084,4 @@
|
||||
"clientPolicies": {
|
||||
"policies": []
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2388,4 +2388,4 @@
|
||||
"clientPolicies": {
|
||||
"policies": []
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,4 +29,3 @@
|
||||
"l1_system_config_address": "0x5531dcff39ec1ec727c4c5d2fc49835368f805a9",
|
||||
"protocol_versions_address": "0x0000000000000000000000000000000000000000"
|
||||
}
|
||||
|
||||
@@ -2388,4 +2388,4 @@
|
||||
"clientPolicies": {
|
||||
"policies": []
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+4
-1
@@ -12,7 +12,10 @@ from fabric import Connection
|
||||
|
||||
|
||||
def dump_src_db_to_file(db_host, db_port, db_user, db_password, db_name, file_name):
|
||||
command = f"pg_dump -h {db_host} -p {db_port} -U {db_user} -d {db_name} -c --inserts -f {file_name}"
|
||||
command = (
|
||||
f"pg_dump -h {db_host} -p {db_port} -U {db_user} "
|
||||
f"-d {db_name} -c --inserts -f {file_name}"
|
||||
)
|
||||
my_env = os.environ.copy()
|
||||
my_env["PGPASSWORD"] = db_password
|
||||
print(f"Exporting from {db_host}:{db_port}/{db_name} to {file_name}... ", end="")
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
|
||||
|
||||
@@ -6,4 +6,4 @@ services:
|
||||
bondId:
|
||||
chainId: laconic_9000-1
|
||||
gas: 250000
|
||||
fees: 200000photon
|
||||
fees: 2000000alnt
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/bin/sh
|
||||
if [[ -n "$CERC_SCRIPT_DEBUG" ]]; then
|
||||
if [ -n "$CERC_SCRIPT_DEBUG" ]; then
|
||||
set -x
|
||||
fi
|
||||
|
||||
@@ -9,7 +9,7 @@ LOGLEVEL="info"
|
||||
laconicd start \
|
||||
--pruning=nothing \
|
||||
--log_level $LOGLEVEL \
|
||||
--minimum-gas-prices=0.0001photon \
|
||||
--minimum-gas-prices=1alnt \
|
||||
--api.enable \
|
||||
--gql-server \
|
||||
--gql-playground
|
||||
|
||||
+1
-1
@@ -1901,4 +1901,4 @@
|
||||
"uid": "b54352dd-35f6-4151-97dc-265bab0c67e9",
|
||||
"version": 18,
|
||||
"weekStart": ""
|
||||
}
|
||||
}
|
||||
|
||||
@@ -849,7 +849,7 @@ groups:
|
||||
annotations:
|
||||
summary: Watcher {{ index $labels "instance" }} of group {{ index $labels "job" }} is falling behind external head by {{ index $values "diff" }}
|
||||
isPaused: false
|
||||
|
||||
|
||||
# Secured Finance
|
||||
- uid: secured_finance_diff_external
|
||||
title: secured_finance_watcher_head_tracking
|
||||
|
||||
@@ -14,7 +14,7 @@ echo ACCOUNT_PRIVATE_KEY=${CERC_PRIVATE_KEY_DEPLOYER} >> .env
|
||||
if [ -f ${erc20_address_file} ]; then
|
||||
echo "${erc20_address_file} already exists, skipping ERC20 contract deployment"
|
||||
cat ${erc20_address_file}
|
||||
|
||||
|
||||
# Keep the container running
|
||||
tail -f
|
||||
fi
|
||||
|
||||
@@ -940,4 +940,3 @@ ALTER TABLE ONLY public.state
|
||||
--
|
||||
-- PostgreSQL database dump complete
|
||||
--
|
||||
|
||||
|
||||
@@ -18,4 +18,3 @@ root@7c4124bb09e3:/src#
|
||||
```
|
||||
|
||||
Now gerbil commands can be run.
|
||||
|
||||
|
||||
+1
-1
@@ -23,7 +23,7 @@ local_npm_registry_url=$2
|
||||
versioned_target_package=$(yarn list --pattern ${target_package} --depth=0 --json --non-interactive --no-progress | jq -r '.data.trees[].name')
|
||||
# Use yarn info to get URL checksums etc from the new registry
|
||||
yarn_info_output=$(yarn info --json $versioned_target_package 2>/dev/null)
|
||||
# First check if the target version actually exists.
|
||||
# First check if the target version actually exists.
|
||||
# If it doesn't exist there will be no .data.dist.tarball element,
|
||||
# and jq will output the string "null"
|
||||
package_tarball=$(echo $yarn_info_output | jq -r .data.dist.tarball)
|
||||
|
||||
+4
-2
@@ -11,6 +11,8 @@ if len(sys.argv) > 1:
|
||||
with open(testnet_config_path) as stream:
|
||||
data = yaml.safe_load(stream)
|
||||
|
||||
for key, value in data['el_premine'].items():
|
||||
acct = w3.eth.account.from_mnemonic(data['mnemonic'], account_path=key, passphrase='')
|
||||
for key, value in data["el_premine"].items():
|
||||
acct = w3.eth.account.from_mnemonic(
|
||||
data["mnemonic"], account_path=key, passphrase=""
|
||||
)
|
||||
print("%s,%s,%s" % (key, acct.address, acct.key.hex()))
|
||||
|
||||
+1
-1
@@ -4,4 +4,4 @@ out = 'out'
|
||||
libs = ['lib']
|
||||
remappings = ['ds-test/=lib/ds-test/src/']
|
||||
|
||||
# See more config options https://github.com/gakonst/foundry/tree/master/config
|
||||
# See more config options https://github.com/gakonst/foundry/tree/master/config
|
||||
|
||||
+1
-1
@@ -20,4 +20,4 @@ contract Stateful {
|
||||
function inc() public {
|
||||
x = x + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -14,7 +14,7 @@ funds_balance=$(echo ${funds_response} | jq -r ".[0].balance[0].quantity")
|
||||
echo "Balance is: ${funds_balance}"
|
||||
|
||||
# Create a bond
|
||||
bond_create_result=$(${registry_command} bond create --type photon --quantity 1000000000)
|
||||
bond_create_result=$(${registry_command} bond create --type alnt --quantity 1000000000)
|
||||
bond_id=$(echo ${bond_create_result} | jq -r .bondId)
|
||||
echo "Created bond with id: ${bond_id}"
|
||||
|
||||
|
||||
+1
-1
@@ -11,4 +11,4 @@ record:
|
||||
foo: bar
|
||||
tags:
|
||||
- a
|
||||
- b
|
||||
- b
|
||||
|
||||
+1
-1
@@ -9,4 +9,4 @@ record:
|
||||
foo: bar
|
||||
tags:
|
||||
- a
|
||||
- b
|
||||
- b
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env bash
|
||||
# Build cerc/laconicd
|
||||
source ${CERC_CONTAINER_BASE_DIR}/build-base.sh
|
||||
docker build -t cerc/laconicd:local ${build_command_args} ${CERC_REPO_BASE_DIR}/laconicd
|
||||
docker build -t cerc/laconicd:local ${build_command_args} ${CERC_REPO_BASE_DIR}/laconicd
|
||||
|
||||
@@ -26,8 +26,14 @@ fi
|
||||
SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
|
||||
WORK_DIR="${1:-/app}"
|
||||
|
||||
if [ -f "${WORK_DIR}/build-webapp.sh" ]; then
|
||||
echo "Building webapp with ${WORK_DIR}/build-webapp.sh ..."
|
||||
cd "${WORK_DIR}" || exit 1
|
||||
|
||||
./build-webapp.sh || exit 1
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [ -f "next.config.mjs" ]; then
|
||||
NEXT_CONFIG_JS="next.config.mjs"
|
||||
IMPORT_OR_REQUIRE="import"
|
||||
|
||||
+34
-26
@@ -30,36 +30,44 @@ fi
|
||||
CERC_WEBAPP_FILES_DIR="${CERC_WEBAPP_FILES_DIR:-/app}"
|
||||
cd "$CERC_WEBAPP_FILES_DIR"
|
||||
|
||||
"$SCRIPT_DIR/apply-runtime-env.sh" "`pwd`" .next .next-r
|
||||
mv .next .next.old
|
||||
mv .next-r/.next .
|
||||
if [ -f "./run-webapp.sh" ]; then
|
||||
echo "Running webapp with run-webapp.sh ..."
|
||||
cd "${WORK_DIR}" || exit 1
|
||||
./run-webapp.sh &
|
||||
tpid=$!
|
||||
wait $tpid
|
||||
else
|
||||
"$SCRIPT_DIR/apply-runtime-env.sh" "`pwd`" .next .next-r
|
||||
mv .next .next.old
|
||||
mv .next-r/.next .
|
||||
|
||||
if [ "$CERC_NEXTJS_SKIP_GENERATE" != "true" ]; then
|
||||
jq -e '.scripts.cerc_generate' package.json >/dev/null
|
||||
if [ $? -eq 0 ]; then
|
||||
npm run cerc_generate > gen.out 2>&1 &
|
||||
tail -f gen.out &
|
||||
tpid=$!
|
||||
if [ "$CERC_NEXTJS_SKIP_GENERATE" != "true" ]; then
|
||||
jq -e '.scripts.cerc_generate' package.json >/dev/null
|
||||
if [ $? -eq 0 ]; then
|
||||
npm run cerc_generate > gen.out 2>&1 &
|
||||
tail -f gen.out &
|
||||
tpid=$!
|
||||
|
||||
count=0
|
||||
generate_done="false"
|
||||
while [ $count -lt $CERC_MAX_GENERATE_TIME ] && [ "$generate_done" == "false" ]; do
|
||||
sleep 1
|
||||
count=$((count + 1))
|
||||
grep 'rendered as static' gen.out > /dev/null
|
||||
if [ $? -eq 0 ]; then
|
||||
generate_done="true"
|
||||
count=0
|
||||
generate_done="false"
|
||||
while [ $count -lt $CERC_MAX_GENERATE_TIME ] && [ "$generate_done" == "false" ]; do
|
||||
sleep 1
|
||||
count=$((count + 1))
|
||||
grep 'rendered as static' gen.out > /dev/null
|
||||
if [ $? -eq 0 ]; then
|
||||
generate_done="true"
|
||||
fi
|
||||
done
|
||||
|
||||
if [ $generate_done != "true" ]; then
|
||||
echo "ERROR: 'npm run cerc_generate' not successful within CERC_MAX_GENERATE_TIME" 1>&2
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
if [ $generate_done != "true" ]; then
|
||||
echo "ERROR: 'npm run cerc_generate' not successful within CERC_MAX_GENERATE_TIME" 1>&2
|
||||
exit 1
|
||||
kill $tpid $(ps -ef | grep node | grep next | grep generate | awk '{print $2}') 2>/dev/null
|
||||
tpid=""
|
||||
fi
|
||||
|
||||
kill $tpid $(ps -ef | grep node | grep next | grep generate | awk '{print $2}') 2>/dev/null
|
||||
tpid=""
|
||||
fi
|
||||
fi
|
||||
|
||||
$CERC_BUILD_TOOL start . -- -p ${CERC_LISTEN_PORT:-80}
|
||||
$CERC_BUILD_TOOL start . -- -p ${CERC_LISTEN_PORT:-80}
|
||||
fi
|
||||
|
||||
@@ -5,4 +5,3 @@ WORKDIR /app
|
||||
COPY . .
|
||||
|
||||
RUN yarn
|
||||
|
||||
|
||||
@@ -4,5 +4,9 @@ source ${CERC_CONTAINER_BASE_DIR}/build-base.sh
|
||||
SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
|
||||
|
||||
# Two-stage build is to allow us to pick up both the upstream repo's files, and local files here for config
|
||||
docker build -t cerc/ping-pub-base:local ${build_command_args} -f $SCRIPT_DIR/Dockerfile.base $CERC_REPO_BASE_DIR/explorer
|
||||
docker build -t cerc/ping-pub-base:local ${build_command_args} -f $SCRIPT_DIR/Dockerfile.base $CERC_REPO_BASE_DIR/cosmos-explorer
|
||||
if [[ $? -ne 0 ]]; then
|
||||
echo "FATAL: Base container build failed, exiting"
|
||||
exit 1
|
||||
fi
|
||||
docker build -t cerc/ping-pub:local ${build_command_args} -f $SCRIPT_DIR/Dockerfile $SCRIPT_DIR
|
||||
|
||||
+5
-5
@@ -7,16 +7,16 @@
|
||||
"rpc": [
|
||||
{"provider": "LX-tendermint-rpc", "address": "LACONIC_LACONICD_RPC_URL"}
|
||||
],
|
||||
"sdk_version": "0.45.1",
|
||||
"sdk_version": "0.50.3",
|
||||
"coin_type": "118",
|
||||
"min_tx_fee": "800",
|
||||
"addr_prefix": "ethm",
|
||||
"addr_prefix": "laconic",
|
||||
"logo": "/logos/cosmos.svg",
|
||||
"assets": [{
|
||||
"base": "photon",
|
||||
"base": "alnt",
|
||||
"symbol": "LNT",
|
||||
"exponent": "6",
|
||||
"coingecko_id": "cosmos",
|
||||
"exponent": "18",
|
||||
"coingecko_id": "cosmos",
|
||||
"logo": "/logos/cosmos.svg"
|
||||
}]
|
||||
}
|
||||
|
||||
+1
-1
@@ -22,7 +22,7 @@ fi
|
||||
# infers the directory from which to load chain configuration files
|
||||
# by the presence or absense of the substring "testnet" in the host name
|
||||
# (browser side -- the host name of the host in the address bar of the browser)
|
||||
# Accordingly we configure our network in both directories in order to
|
||||
# Accordingly we configure our network in both directories in order to
|
||||
# subvert this lunacy.
|
||||
explorer_mainnet_config_dir=/app/chains/mainnet
|
||||
explorer_testnet_config_dir=/app/chains/testnet
|
||||
|
||||
@@ -2,4 +2,4 @@
|
||||
# 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
|
||||
docker build -t cerc/test-database-client:local -f ${SCRIPT_DIR}/Dockerfile ${build_command_args} $SCRIPT_DIR
|
||||
|
||||
+1
-1
@@ -8,7 +8,7 @@ CERC_WEBAPP_FILES_DIR="${CERC_WEBAPP_FILES_DIR:-/data}"
|
||||
CERC_ENABLE_CORS="${CERC_ENABLE_CORS:-false}"
|
||||
CERC_SINGLE_PAGE_APP="${CERC_SINGLE_PAGE_APP}"
|
||||
|
||||
if [ -z "${CERC_SINGLE_PAGE_APP}" ]; then
|
||||
if [ -z "${CERC_SINGLE_PAGE_APP}" ]; then
|
||||
# If there is only one HTML file, assume an SPA.
|
||||
if [ 1 -eq $(find "${CERC_WEBAPP_FILES_DIR}" -name '*.html' | wc -l) ]; then
|
||||
CERC_SINGLE_PAGE_APP=true
|
||||
|
||||
@@ -0,0 +1,260 @@
|
||||
# Caddy Ingress Controller for kind
|
||||
# Based on: https://github.com/caddyserver/ingress
|
||||
# Provides automatic HTTPS with Let's Encrypt
|
||||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
name: caddy-system
|
||||
labels:
|
||||
app.kubernetes.io/name: caddy-ingress-controller
|
||||
app.kubernetes.io/instance: caddy-ingress
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
name: caddy-ingress-controller
|
||||
namespace: caddy-system
|
||||
labels:
|
||||
app.kubernetes.io/name: caddy-ingress-controller
|
||||
app.kubernetes.io/instance: caddy-ingress
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
name: caddy-ingress-controller
|
||||
labels:
|
||||
app.kubernetes.io/name: caddy-ingress-controller
|
||||
app.kubernetes.io/instance: caddy-ingress
|
||||
rules:
|
||||
- apiGroups:
|
||||
- ""
|
||||
resources:
|
||||
- configmaps
|
||||
- endpoints
|
||||
- nodes
|
||||
- pods
|
||||
- namespaces
|
||||
- services
|
||||
verbs:
|
||||
- list
|
||||
- watch
|
||||
- get
|
||||
- apiGroups:
|
||||
- ""
|
||||
resources:
|
||||
- secrets
|
||||
verbs:
|
||||
- list
|
||||
- watch
|
||||
- get
|
||||
- create
|
||||
- update
|
||||
- delete
|
||||
- apiGroups:
|
||||
- ""
|
||||
resources:
|
||||
- nodes
|
||||
verbs:
|
||||
- get
|
||||
- apiGroups:
|
||||
- ""
|
||||
resources:
|
||||
- events
|
||||
verbs:
|
||||
- create
|
||||
- patch
|
||||
- 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
|
||||
resources:
|
||||
- leases
|
||||
verbs:
|
||||
- get
|
||||
- create
|
||||
- update
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRoleBinding
|
||||
metadata:
|
||||
name: caddy-ingress-controller
|
||||
labels:
|
||||
app.kubernetes.io/name: caddy-ingress-controller
|
||||
app.kubernetes.io/instance: caddy-ingress
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: ClusterRole
|
||||
name: caddy-ingress-controller
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: caddy-ingress-controller
|
||||
namespace: caddy-system
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: caddy-ingress-controller-configmap
|
||||
namespace: caddy-system
|
||||
labels:
|
||||
app.kubernetes.io/name: caddy-ingress-controller
|
||||
app.kubernetes.io/instance: caddy-ingress
|
||||
data:
|
||||
# Caddy global options
|
||||
acmeCA: "https://acme-v02.api.letsencrypt.org/directory"
|
||||
email: ""
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: caddy-ingress-controller
|
||||
namespace: caddy-system
|
||||
labels:
|
||||
app.kubernetes.io/name: caddy-ingress-controller
|
||||
app.kubernetes.io/instance: caddy-ingress
|
||||
app.kubernetes.io/component: controller
|
||||
spec:
|
||||
type: NodePort
|
||||
ports:
|
||||
- name: http
|
||||
port: 80
|
||||
targetPort: http
|
||||
protocol: TCP
|
||||
- name: https
|
||||
port: 443
|
||||
targetPort: https
|
||||
protocol: TCP
|
||||
selector:
|
||||
app.kubernetes.io/name: caddy-ingress-controller
|
||||
app.kubernetes.io/instance: caddy-ingress
|
||||
app.kubernetes.io/component: controller
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: caddy-ingress-controller
|
||||
namespace: caddy-system
|
||||
labels:
|
||||
app.kubernetes.io/name: caddy-ingress-controller
|
||||
app.kubernetes.io/instance: caddy-ingress
|
||||
app.kubernetes.io/component: controller
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: caddy-ingress-controller
|
||||
app.kubernetes.io/instance: caddy-ingress
|
||||
app.kubernetes.io/component: controller
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app.kubernetes.io/name: caddy-ingress-controller
|
||||
app.kubernetes.io/instance: caddy-ingress
|
||||
app.kubernetes.io/component: controller
|
||||
spec:
|
||||
serviceAccountName: caddy-ingress-controller
|
||||
terminationGracePeriodSeconds: 60
|
||||
nodeSelector:
|
||||
ingress-ready: "true"
|
||||
kubernetes.io/os: linux
|
||||
tolerations:
|
||||
- effect: NoSchedule
|
||||
key: node-role.kubernetes.io/master
|
||||
operator: Equal
|
||||
- effect: NoSchedule
|
||||
key: node-role.kubernetes.io/control-plane
|
||||
operator: Equal
|
||||
containers:
|
||||
- name: caddy-ingress-controller
|
||||
image: caddy/ingress:latest
|
||||
imagePullPolicy: IfNotPresent
|
||||
ports:
|
||||
- name: http
|
||||
containerPort: 80
|
||||
hostPort: 80
|
||||
protocol: TCP
|
||||
- name: https
|
||||
containerPort: 443
|
||||
hostPort: 443
|
||||
protocol: TCP
|
||||
env:
|
||||
- name: POD_NAME
|
||||
valueFrom:
|
||||
fieldRef:
|
||||
fieldPath: metadata.name
|
||||
- name: POD_NAMESPACE
|
||||
valueFrom:
|
||||
fieldRef:
|
||||
fieldPath: metadata.namespace
|
||||
args:
|
||||
- -config-map=caddy-system/caddy-ingress-controller-configmap
|
||||
- -class-name=caddy
|
||||
resources:
|
||||
requests:
|
||||
cpu: 100m
|
||||
memory: 128Mi
|
||||
limits:
|
||||
cpu: 1000m
|
||||
memory: 512Mi
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: /healthz
|
||||
port: 9765
|
||||
initialDelaySeconds: 3
|
||||
periodSeconds: 10
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /healthz
|
||||
port: 9765
|
||||
initialDelaySeconds: 3
|
||||
periodSeconds: 10
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: true
|
||||
capabilities:
|
||||
add:
|
||||
- NET_BIND_SERVICE
|
||||
drop:
|
||||
- ALL
|
||||
runAsUser: 0
|
||||
runAsGroup: 0
|
||||
volumeMounts:
|
||||
- name: caddy-data
|
||||
mountPath: /data
|
||||
- name: caddy-config
|
||||
mountPath: /config
|
||||
volumes:
|
||||
- name: caddy-data
|
||||
emptyDir: {}
|
||||
- name: caddy-config
|
||||
emptyDir: {}
|
||||
---
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: IngressClass
|
||||
metadata:
|
||||
name: caddy
|
||||
labels:
|
||||
app.kubernetes.io/name: caddy-ingress-controller
|
||||
app.kubernetes.io/instance: caddy-ingress
|
||||
annotations:
|
||||
ingressclass.kubernetes.io/is-default-class: "true"
|
||||
spec:
|
||||
controller: caddy.io/ingress-controller
|
||||
@@ -6,7 +6,7 @@ JS/TS/NPM builds need an npm registry to store intermediate package artifacts.
|
||||
This can be supplied by the user (e.g. using a hosted registry or even npmjs.com), or a local registry using gitea can be deployed by stack orchestrator.
|
||||
To use a user-supplied registry set these environment variables:
|
||||
|
||||
`CERC_NPM_REGISTRY_URL` and
|
||||
`CERC_NPM_REGISTRY_URL` and
|
||||
`CERC_NPM_AUTH_TOKEN`
|
||||
|
||||
Leave `CERC_NPM_REGISTRY_URL` un-set to use the local gitea registry.
|
||||
@@ -22,7 +22,7 @@ $ laconic-so --stack build-support build-containers
|
||||
|
||||
```
|
||||
$ laconic-so --stack package-registry setup-repositories
|
||||
$ laconic-so --stack package-registry build-containers
|
||||
$ laconic-so --stack package-registry build-containers
|
||||
$ laconic-so --stack package-registry deploy up
|
||||
[+] Running 3/3
|
||||
⠿ Network laconic-aecc4a21d3a502b14522db97d427e850_gitea Created 0.0s
|
||||
|
||||
@@ -14,4 +14,3 @@ containers:
|
||||
pods:
|
||||
- fixturenet-blast
|
||||
- foundry
|
||||
|
||||
@@ -3,4 +3,3 @@
|
||||
A "loaded" version of fixturenet-eth, with all the bells and whistles enabled.
|
||||
|
||||
TODO: write me
|
||||
|
||||
|
||||
@@ -64,5 +64,6 @@ $ laconic-so --stack fixturenet-laconic-loaded deploy exec cli ./scripts/create-
|
||||
Balance is: 99998999999999998999600000
|
||||
Created bond with id: dd88e8d6f9567b32b28e70552aea4419c5dd3307ebae85a284d1fe38904e301a
|
||||
Published demo-record-1.yml with id: bafyreierh3xnfivexlscdwubvczmddsnf46uytyfvrbdhkjzztvsz6ruly
|
||||
...
|
||||
```
|
||||
The published record should be visible in the console.
|
||||
The published records should be visible in the console.
|
||||
|
||||
@@ -30,4 +30,3 @@ config:
|
||||
cli:
|
||||
key: laconicd.mykey
|
||||
address: laconicd.myaddress
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ $ chmod +x ./laconic-so
|
||||
$ export PATH=$PATH:$(pwd) # Or move laconic-so to ~/bin or your favorite on-path directory
|
||||
```
|
||||
## 2. Prepare the local build environment
|
||||
Note that this step needs only to be done once on a new machine.
|
||||
Note that this step needs only to be done once on a new machine.
|
||||
Detailed instructions can be found [here](../build-support/README.md). For the impatient run these commands:
|
||||
```
|
||||
$ laconic-so --stack build-support build-containers --exclude cerc/builder-gerbil
|
||||
|
||||
@@ -52,7 +52,7 @@ laconic-so --stack fixturenet-optimism deploy init --map-ports-to-host any-fixed
|
||||
It is usually necessary to expose certain container ports on one or more the host's addresses to allow incoming connections.
|
||||
Any ports defined in the Docker compose file are exposed by default with random port assignments, bound to "any" interface (IP address 0.0.0.0), but the port mappings can be customized by editing the "spec" file generated by `laconic-so deploy init`.
|
||||
|
||||
In addition, a stack-wide port mapping "recipe" can be applied at the time the
|
||||
In addition, a stack-wide port mapping "recipe" can be applied at the time the
|
||||
`laconic-so deploy init` command is run, by supplying the desired recipe with the `--map-ports-to-host` option. The following recipes are supported:
|
||||
| Recipe | Host Port Mapping |
|
||||
|--------|-------------------|
|
||||
@@ -62,11 +62,11 @@ In addition, a stack-wide port mapping "recipe" can be applied at the time the
|
||||
| localhost-fixed-random | Bind to 127.0.0.1 using a random port number selected at the time the command is run (not checked for already in use)|
|
||||
| any-fixed-random | Bind to 0.0.0.0 using a random port number selected at the time the command is run (not checked for already in use) |
|
||||
|
||||
For example, you may wish to use `any-fixed-random` to generate the initial mappings and then edit the spec file to set the `fixturenet-eth-geth-1` RPC to port 8545 and the `op-geth` RPC to port 9545 on the host.
|
||||
For example, you may wish to use `any-fixed-random` to generate the initial mappings and then edit the spec file to set the `fixturenet-eth-geth-1` RPC to port 8545 and the `op-geth` RPC to port 9545 on the host.
|
||||
|
||||
Or, you may wish to use `any-same` for the initial mappings -- in which case you'll have to edit the spec to file to ensure the various geth instances aren't all trying to publish to host ports 8545/8546 at once.
|
||||
|
||||
### Data volumes
|
||||
### Data volumes
|
||||
Container data volumes are bind-mounted to specified paths in the host filesystem.
|
||||
The default setup (generated by `laconic-so deploy init`) places the volumes in the `./data` subdirectory of the deployment directory. The default mappings can be customized by editing the "spec" file generated by `laconic-so deploy init`.
|
||||
|
||||
@@ -101,7 +101,7 @@ docker logs -f <CONTAINER_ID>
|
||||
|
||||
## Example: bridge some ETH from L1 to L2
|
||||
|
||||
Send some ETH from the desired account to the `L1StandardBridgeProxy` contract on L1 to test bridging to L2.
|
||||
Send some ETH from the desired account to the `L1StandardBridgeProxy` contract on L1 to test bridging to L2.
|
||||
|
||||
We can use the testing account `0xe6CE22afe802CAf5fF7d3845cec8c736ecc8d61F` which is pre-funded and unlocked, and the `cerc/foundry:local` container to make use of the `cast` cli.
|
||||
|
||||
|
||||
@@ -18,21 +18,26 @@ from ruamel.yaml import YAML
|
||||
|
||||
|
||||
def create(context: DeploymentContext, extra_args):
|
||||
# Slightly modify the base fixturenet-eth compose file to replace the startup script for fixturenet-eth-geth-1
|
||||
# We need to start geth with the flag to allow non eip-155 compliant transactions in order to publish the
|
||||
# deterministic-deployment-proxy contract, which itself is a prereq for Optimism contract deployment
|
||||
fixturenet_eth_compose_file = context.deployment_dir.joinpath('compose', 'docker-compose-fixturenet-eth.yml')
|
||||
# Slightly modify the base fixturenet-eth compose file to replace the
|
||||
# startup script for fixturenet-eth-geth-1
|
||||
# We need to start geth with the flag to allow non eip-155 compliant
|
||||
# transactions in order to publish the
|
||||
# deterministic-deployment-proxy contract, which itself is a prereq for
|
||||
# Optimism contract deployment
|
||||
fixturenet_eth_compose_file = context.deployment_dir.joinpath(
|
||||
"compose", "docker-compose-fixturenet-eth.yml"
|
||||
)
|
||||
|
||||
with open(fixturenet_eth_compose_file, 'r') as yaml_file:
|
||||
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'
|
||||
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)
|
||||
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:
|
||||
with open(fixturenet_eth_compose_file, "w") as yaml_file:
|
||||
yaml = YAML()
|
||||
yaml.dump(yaml_data, yaml_file)
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ laconic-so --stack fixturenet-optimism deploy init --map-ports-to-host any-fixed
|
||||
It is usually necessary to expose certain container ports on one or more the host's addresses to allow incoming connections.
|
||||
Any ports defined in the Docker compose file are exposed by default with random port assignments, bound to "any" interface (IP address 0.0.0.0), but the port mappings can be customized by editing the "spec" file generated by `laconic-so deploy init`.
|
||||
|
||||
In addition, a stack-wide port mapping "recipe" can be applied at the time the
|
||||
In addition, a stack-wide port mapping "recipe" can be applied at the time the
|
||||
`laconic-so deploy init` command is run, by supplying the desired recipe with the `--map-ports-to-host` option. The following recipes are supported:
|
||||
| Recipe | Host Port Mapping |
|
||||
|--------|-------------------|
|
||||
@@ -48,9 +48,9 @@ In addition, a stack-wide port mapping "recipe" can be applied at the time the
|
||||
| localhost-fixed-random | Bind to 127.0.0.1 using a random port number selected at the time the command is run (not checked for already in use)|
|
||||
| any-fixed-random | Bind to 0.0.0.0 using a random port number selected at the time the command is run (not checked for already in use) |
|
||||
|
||||
For example, you may wish to use `any-fixed-random` to generate the initial mappings and then edit the spec file to set the `op-geth` RPC to an easy to remember port like 8545 or 9545 on the host.
|
||||
For example, you may wish to use `any-fixed-random` to generate the initial mappings and then edit the spec file to set the `op-geth` RPC to an easy to remember port like 8545 or 9545 on the host.
|
||||
|
||||
### Data volumes
|
||||
### Data volumes
|
||||
Container data volumes are bind-mounted to specified paths in the host filesystem.
|
||||
The default setup (generated by `laconic-so deploy init`) places the volumes in the `./data` subdirectory of the deployment directory. The default mappings can be customized by editing the "spec" file generated by `laconic-so deploy init`.
|
||||
|
||||
|
||||
@@ -128,7 +128,7 @@ Stack components:
|
||||
removed
|
||||
topics
|
||||
transactionHash
|
||||
transactionIndex
|
||||
transactionIndex
|
||||
}
|
||||
|
||||
getEthBlock(
|
||||
@@ -211,14 +211,14 @@ Stack components:
|
||||
hash
|
||||
}
|
||||
log {
|
||||
id
|
||||
id
|
||||
}
|
||||
block {
|
||||
number
|
||||
}
|
||||
}
|
||||
metadata {
|
||||
pageEndsAtTimestamp
|
||||
pageEndsAtTimestamp
|
||||
isLastPage
|
||||
}
|
||||
}
|
||||
@@ -227,7 +227,7 @@ Stack components:
|
||||
* Open watcher Ponder app endpoint http://localhost:42069
|
||||
|
||||
* Try GQL query to see transfer events
|
||||
|
||||
|
||||
```graphql
|
||||
{
|
||||
transferEvents (orderBy: "timestamp", orderDirection: "desc") {
|
||||
@@ -251,9 +251,9 @@ Stack components:
|
||||
```bash
|
||||
export TOKEN_ADDRESS=$(docker exec payments-ponder-er20-contracts-1 jq -r '.address' ./deployment/erc20-address.json)
|
||||
```
|
||||
|
||||
|
||||
* Transfer token
|
||||
|
||||
|
||||
```bash
|
||||
docker exec -it payments-ponder-er20-contracts-1 bash -c "yarn token:transfer:docker --token ${TOKEN_ADDRESS} --to 0xe22AD83A0dE117bA0d03d5E94Eb4E0d80a69C62a --amount 5000"
|
||||
```
|
||||
|
||||
@@ -48,7 +48,7 @@ or see the full logs:
|
||||
$ laconic-so --stack fixturenet-pocket deploy logs pocket
|
||||
```
|
||||
## 5. Send a relay request to Pocket node
|
||||
The Pocket node serves relay requests at `http://localhost:8081/v1/client/sim`
|
||||
The Pocket node serves relay requests at `http://localhost:8081/v1/client/sim`
|
||||
|
||||
Example request:
|
||||
```
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user