forked from cerc-io/stack-orchestrator
Compare commits
10
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4a44ade2e8 | ||
|
|
6976deb76e | ||
|
|
e13d3f63c4 | ||
|
|
30db1f58d0 | ||
|
|
09a1cbb966 | ||
|
|
13ce521d84 | ||
|
|
6e4dae9777 | ||
|
|
9043a67c7c | ||
|
|
7f84a45cfd | ||
|
|
4126f2fc43 |
@@ -0,0 +1,58 @@
|
||||
name: External Stack Test
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: '*'
|
||||
paths:
|
||||
- '!**'
|
||||
- '.gitea/workflows/triggers/test-external-stack'
|
||||
- '.gitea/workflows/test-external-stack.yml'
|
||||
- 'tests/external-stack/run-test.sh'
|
||||
schedule: # Note: coordinate with other tests to not overload runners at the same time of day
|
||||
- cron: '8 19 * * *'
|
||||
|
||||
jobs:
|
||||
test:
|
||||
name: "Run external stack test suite"
|
||||
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 external stack tests"
|
||||
run: ./tests/external-stack/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 }}
|
||||
@@ -0,0 +1,2 @@
|
||||
Change this file to trigger running the external-stack CI job
|
||||
trigger
|
||||
@@ -71,7 +71,7 @@ def process_container(build_context: BuildContext) -> bool:
|
||||
|
||||
# Check if this is in an external stack
|
||||
if stack_is_external(build_context.stack):
|
||||
container_parent_dir = Path(build_context.stack).joinpath("container-build")
|
||||
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.
|
||||
|
||||
@@ -3,7 +3,7 @@ services:
|
||||
restart: always
|
||||
hostname: fixturenet-eth-bootnode-geth
|
||||
env_file:
|
||||
- ../config/fixturenet-eth/fixturenet-eth.env
|
||||
- ../config/fixturenet-plugeth/fixturenet-eth.env
|
||||
environment:
|
||||
RUN_BOOTNODE: "true"
|
||||
CERC_SCRIPT_DEBUG: ${CERC_SCRIPT_DEBUG}
|
||||
@@ -24,8 +24,9 @@ services:
|
||||
CERC_RUN_STATEDIFF: ${CERC_RUN_STATEDIFF:-detect}
|
||||
CERC_STATEDIFF_DB_NODE_ID: 1
|
||||
CERC_SCRIPT_DEBUG: ${CERC_SCRIPT_DEBUG}
|
||||
CERC_ALLOW_UNPROTECTED_TXS: ${CERC_ALLOW_UNPROTECTED_TXS:-false}
|
||||
env_file:
|
||||
- ../config/fixturenet-eth/fixturenet-eth.env
|
||||
- ../config/fixturenet-plugeth/fixturenet-eth.env
|
||||
image: cerc/fixturenet-plugeth-plugeth:local
|
||||
volumes:
|
||||
- fixturenet_plugeth_geth_1_data:/root/ethdata
|
||||
@@ -55,7 +56,7 @@ services:
|
||||
environment:
|
||||
CERC_KEEP_RUNNING_AFTER_GETH_EXIT: "true"
|
||||
env_file:
|
||||
- ../config/fixturenet-eth/fixturenet-eth.env
|
||||
- ../config/fixturenet-plugeth/fixturenet-eth.env
|
||||
image: cerc/fixturenet-plugeth-plugeth:local
|
||||
depends_on:
|
||||
- fixturenet-eth-bootnode-geth
|
||||
@@ -82,7 +83,7 @@ services:
|
||||
retries: 10
|
||||
start_period: 30s
|
||||
env_file:
|
||||
- ../config/fixturenet-eth/fixturenet-eth.env
|
||||
- ../config/fixturenet-plugeth/fixturenet-eth.env
|
||||
environment:
|
||||
NODE_NUMBER: "1"
|
||||
ETH1_ENDPOINT: "http://fixturenet-eth-geth-1:8545"
|
||||
@@ -108,7 +109,7 @@ services:
|
||||
retries: 10
|
||||
start_period: 30s
|
||||
env_file:
|
||||
- ../config/fixturenet-eth/fixturenet-eth.env
|
||||
- ../config/fixturenet-plugeth/fixturenet-eth.env
|
||||
environment:
|
||||
NODE_NUMBER: "2"
|
||||
ETH1_ENDPOINT: "http://fixturenet-eth-geth-2:8545"
|
||||
|
||||
@@ -16,8 +16,12 @@ services:
|
||||
postgres_pass: password
|
||||
postgres_db: graph-node
|
||||
ethereum: ${ETH_NETWORKS:-lotus-fixturenet:http://lotus-node-1:1234/rpc/v1}
|
||||
# Env varaibles reference: https://git.vdb.to/cerc-io/graph-node/src/branch/master/docs/environment-variables.md
|
||||
GRAPH_LOG: debug
|
||||
ETHEREUM_REORG_THRESHOLD: 3
|
||||
GRAPH_ETHEREUM_JSON_RPC_TIMEOUT: ${GRAPH_ETHEREUM_JSON_RPC_TIMEOUT:-180}
|
||||
GRAPH_ETHEREUM_REQUEST_RETRIES: ${GRAPH_ETHEREUM_REQUEST_RETRIES:-10}
|
||||
GRAPH_ETHEREUM_MAX_BLOCK_RANGE_SIZE: ${GRAPH_ETHEREUM_MAX_BLOCK_RANGE_SIZE:-2000}
|
||||
entrypoint: ["bash", "-c"]
|
||||
# Wait for ETH RPC endpoint to be up when running with fixturenet-lotus
|
||||
command: |
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
# The password used to access test accounts (eg, via personal_unlockAccount). The password is the same for all accounts.
|
||||
ACCOUNT_PASSWORD=secret1212
|
||||
|
||||
# ENODE of the geth bootnode.
|
||||
BOOTNODE_KEY="b0ac22adcad37213c7c565810a50f1772291e7b0ce53fb73e7ec2a3c75bc13b5"
|
||||
ENODE="enode://af22c29c316ad069cf48a09a4ad5cf04a251b411e45098888d114c6dd7f489a13786620d5953738762afa13711d4ffb3b19aa5de772d8af72f851f7e9c5b164a@fixturenet-eth-bootnode-geth:30303"
|
||||
|
||||
# JWT shared by geth and lighthouse for authentication.
|
||||
JWT="0x6cdcac3501046a08e186730dd8bd136cfaf0fdc1fc955f6e15ad3068c0ff2af0"
|
||||
|
||||
# URL to download the ENR of the lighthouse bootnode (generated at first start).
|
||||
ENR_URL="http://fixturenet-eth-bootnode-lighthouse:3000/bootnode/enr.dat"
|
||||
|
||||
# DB connection settings for statediffing (see docker-compose-db.yml)
|
||||
CERC_STATEDIFF_DB_HOST="ipld-eth-db"
|
||||
CERC_STATEDIFF_DB_PORT=5432
|
||||
CERC_STATEDIFF_DB_NAME="cerc_testing"
|
||||
CERC_STATEDIFF_DB_USER="vdbm"
|
||||
CERC_STATEDIFF_DB_PASSWORD="password"
|
||||
CERC_STATEDIFF_DB_GOOSE_MIN_VER=${CERC_STATEDIFF_DB_GOOSE_MIN_VER:-18}
|
||||
CERC_STATEDIFF_DB_LOG_STATEMENTS="${CERC_STATEDIFF_DB_LOG_STATEMENTS:-false}"
|
||||
CERC_STATEDIFF_WORKERS=2
|
||||
|
||||
CERC_GETH_VMODULE="statediff/*=5,rpc/*=5"
|
||||
CERC_GETH_VERBOSITY=${CERC_GETH_VERBOSITY:-3}
|
||||
|
||||
# Used by Lighthouse
|
||||
SECONDS_PER_ETH1_BLOCK=${SECONDS_PER_ETH1_BLOCK:-3}
|
||||
@@ -1,147 +0,0 @@
|
||||
apiVersion: 1
|
||||
groups:
|
||||
- orgId: 1
|
||||
name: blackbox
|
||||
folder: BlackboxAlerts
|
||||
interval: 30s
|
||||
rules:
|
||||
# Azimuth Gateway endpoint
|
||||
- uid: azimuth_gateway
|
||||
title: azimuth_gateway_endpoint_tracking
|
||||
condition: condition
|
||||
data:
|
||||
- refId: probe
|
||||
relativeTimeRange:
|
||||
from: 600
|
||||
to: 0
|
||||
datasourceUid: PBFA97CFB590B2093
|
||||
model:
|
||||
editorMode: code
|
||||
expr: probe_success{destination="azimuth_gateway"}
|
||||
instant: true
|
||||
intervalMs: 1000
|
||||
legendFormat: __auto
|
||||
maxDataPoints: 43200
|
||||
range: false
|
||||
refId: probe
|
||||
- refId: http_status_code
|
||||
relativeTimeRange:
|
||||
from: 600
|
||||
to: 0
|
||||
datasourceUid: PBFA97CFB590B2093
|
||||
model:
|
||||
editorMode: code
|
||||
expr: probe_http_status_code{destination="azimuth_gateway"}
|
||||
instant: true
|
||||
intervalMs: 1000
|
||||
legendFormat: __auto
|
||||
maxDataPoints: 43200
|
||||
range: false
|
||||
refId: http_status_code
|
||||
- refId: condition
|
||||
relativeTimeRange:
|
||||
from: 600
|
||||
to: 0
|
||||
datasourceUid: __expr__
|
||||
model:
|
||||
conditions:
|
||||
- evaluator:
|
||||
params:
|
||||
- 0
|
||||
- 0
|
||||
type: gt
|
||||
operator:
|
||||
type: and
|
||||
query:
|
||||
params: []
|
||||
reducer:
|
||||
params: []
|
||||
type: avg
|
||||
type: query
|
||||
datasource:
|
||||
name: Expression
|
||||
type: __expr__
|
||||
uid: __expr__
|
||||
expression: ${probe} != 1 || ${http_status_code} != 200
|
||||
intervalMs: 1000
|
||||
maxDataPoints: 43200
|
||||
refId: condition
|
||||
type: math
|
||||
noDataState: Alerting
|
||||
execErrState: Alerting
|
||||
for: 5m
|
||||
annotations:
|
||||
summary: Probe failed for Azimuth gateway endpoint
|
||||
labels:
|
||||
probe_success: '{{ index $values "probe" }}'
|
||||
isPaused: false
|
||||
# Laconicd GQL endpoint
|
||||
- uid: laconicd_gql
|
||||
title: laconicd_gql_endpoint_tracking
|
||||
condition: condition
|
||||
data:
|
||||
- refId: probe
|
||||
relativeTimeRange:
|
||||
from: 600
|
||||
to: 0
|
||||
datasourceUid: PBFA97CFB590B2093
|
||||
model:
|
||||
editorMode: code
|
||||
expr: probe_success{destination="laconicd_gql"}
|
||||
instant: true
|
||||
intervalMs: 1000
|
||||
legendFormat: __auto
|
||||
maxDataPoints: 43200
|
||||
range: false
|
||||
refId: probe
|
||||
- refId: http_status_code
|
||||
relativeTimeRange:
|
||||
from: 600
|
||||
to: 0
|
||||
datasourceUid: PBFA97CFB590B2093
|
||||
model:
|
||||
editorMode: code
|
||||
expr: probe_http_status_code{destination="laconicd_gql"}
|
||||
instant: true
|
||||
intervalMs: 1000
|
||||
legendFormat: __auto
|
||||
maxDataPoints: 43200
|
||||
range: false
|
||||
refId: http_status_code
|
||||
- refId: condition
|
||||
relativeTimeRange:
|
||||
from: 600
|
||||
to: 0
|
||||
datasourceUid: __expr__
|
||||
model:
|
||||
conditions:
|
||||
- evaluator:
|
||||
params:
|
||||
- 0
|
||||
- 0
|
||||
type: gt
|
||||
operator:
|
||||
type: and
|
||||
query:
|
||||
params: []
|
||||
reducer:
|
||||
params: []
|
||||
type: avg
|
||||
type: query
|
||||
datasource:
|
||||
name: Expression
|
||||
type: __expr__
|
||||
uid: __expr__
|
||||
expression: ${probe} != 1 || ${http_status_code} != 200
|
||||
intervalMs: 1000
|
||||
maxDataPoints: 43200
|
||||
refId: condition
|
||||
type: math
|
||||
noDataState: Alerting
|
||||
execErrState: Alerting
|
||||
for: 5m
|
||||
annotations:
|
||||
summary: Probe failed for Laconicd GQL endpoint
|
||||
labels:
|
||||
probe_success: '{{ index $values "probe" }}'
|
||||
isPaused: false
|
||||
+1
-1
@@ -49,7 +49,7 @@
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 3,
|
||||
"w": 4,
|
||||
"w": 3,
|
||||
"x": 0,
|
||||
"y": 0
|
||||
},
|
||||
|
||||
@@ -24,10 +24,9 @@ scrape_configs:
|
||||
params:
|
||||
module: [http_2xx]
|
||||
static_configs:
|
||||
# Add URLs for targets to be monitored below
|
||||
# - targets: [https://github.com]
|
||||
# labels:
|
||||
# destination: 'github'
|
||||
# Add URLs to be monitored below
|
||||
- targets:
|
||||
# - https://github.com
|
||||
relabel_configs:
|
||||
- source_labels: [__address__]
|
||||
regex: (.*)(:80)?
|
||||
|
||||
@@ -59,29 +59,29 @@ groups:
|
||||
conditions:
|
||||
- evaluator:
|
||||
params:
|
||||
- 15
|
||||
- 0
|
||||
- 0
|
||||
type: gt
|
||||
operator:
|
||||
type: when
|
||||
type: and
|
||||
query:
|
||||
params:
|
||||
- diff
|
||||
params: []
|
||||
reducer:
|
||||
params: []
|
||||
type: last
|
||||
type: avg
|
||||
type: query
|
||||
datasource:
|
||||
name: Expression
|
||||
type: __expr__
|
||||
uid: __expr__
|
||||
expression: ""
|
||||
hide: false
|
||||
expression: ${diff} >= 16
|
||||
intervalMs: 1000
|
||||
maxDataPoints: 43200
|
||||
refId: condition
|
||||
type: classic_conditions
|
||||
type: math
|
||||
noDataState: Alerting
|
||||
execErrState: Alerting
|
||||
for: 5m
|
||||
for: 15m
|
||||
annotations:
|
||||
summary: Watcher {{ index $labels "instance" }} of group {{ index $labels "job" }} is falling behind external head by {{ index $values "diff" }}
|
||||
isPaused: false
|
||||
@@ -135,29 +135,29 @@ groups:
|
||||
conditions:
|
||||
- evaluator:
|
||||
params:
|
||||
- 15
|
||||
- 0
|
||||
- 0
|
||||
type: gt
|
||||
operator:
|
||||
type: when
|
||||
type: and
|
||||
query:
|
||||
params:
|
||||
- diff
|
||||
params: []
|
||||
reducer:
|
||||
params: []
|
||||
type: last
|
||||
type: avg
|
||||
type: query
|
||||
datasource:
|
||||
name: Expression
|
||||
type: __expr__
|
||||
uid: __expr__
|
||||
expression: ""
|
||||
hide: false
|
||||
expression: ${diff} >= 16
|
||||
intervalMs: 1000
|
||||
maxDataPoints: 43200
|
||||
refId: condition
|
||||
type: classic_conditions
|
||||
type: math
|
||||
noDataState: Alerting
|
||||
execErrState: Alerting
|
||||
for: 5m
|
||||
for: 15m
|
||||
annotations:
|
||||
summary: Watcher {{ index $labels "instance" }} of group {{ index $labels "job" }} is falling behind external head by {{ index $values "diff" }}
|
||||
isPaused: false
|
||||
@@ -202,7 +202,7 @@ groups:
|
||||
legendFormat: __auto
|
||||
range: false
|
||||
refId: latest_external
|
||||
- refId: condition
|
||||
- refId: condition
|
||||
relativeTimeRange:
|
||||
from: 600
|
||||
to: 0
|
||||
@@ -211,29 +211,29 @@ groups:
|
||||
conditions:
|
||||
- evaluator:
|
||||
params:
|
||||
- 15
|
||||
- 0
|
||||
- 0
|
||||
type: gt
|
||||
operator:
|
||||
type: when
|
||||
type: and
|
||||
query:
|
||||
params:
|
||||
- diff
|
||||
params: []
|
||||
reducer:
|
||||
params: []
|
||||
type: last
|
||||
type: avg
|
||||
type: query
|
||||
datasource:
|
||||
name: Expression
|
||||
type: __expr__
|
||||
uid: __expr__
|
||||
expression: ""
|
||||
hide: false
|
||||
expression: ${diff} >= 16
|
||||
intervalMs: 1000
|
||||
maxDataPoints: 43200
|
||||
refId: condition
|
||||
type: classic_conditions
|
||||
type: math
|
||||
noDataState: Alerting
|
||||
execErrState: Alerting
|
||||
for: 5m
|
||||
for: 15m
|
||||
annotations:
|
||||
summary: Watcher {{ index $labels "instance" }} of group {{ index $labels "job" }} is falling behind external head by {{ index $values "diff" }}
|
||||
isPaused: false
|
||||
@@ -278,7 +278,7 @@ groups:
|
||||
legendFormat: __auto
|
||||
range: false
|
||||
refId: latest_external
|
||||
- refId: condition
|
||||
- refId: condition
|
||||
relativeTimeRange:
|
||||
from: 600
|
||||
to: 0
|
||||
@@ -287,29 +287,29 @@ groups:
|
||||
conditions:
|
||||
- evaluator:
|
||||
params:
|
||||
- 15
|
||||
- 0
|
||||
- 0
|
||||
type: gt
|
||||
operator:
|
||||
type: when
|
||||
type: and
|
||||
query:
|
||||
params:
|
||||
- diff
|
||||
params: []
|
||||
reducer:
|
||||
params: []
|
||||
type: last
|
||||
type: avg
|
||||
type: query
|
||||
datasource:
|
||||
name: Expression
|
||||
type: __expr__
|
||||
uid: __expr__
|
||||
expression: ""
|
||||
hide: false
|
||||
expression: ${diff} >= 16
|
||||
intervalMs: 1000
|
||||
maxDataPoints: 43200
|
||||
refId: condition
|
||||
type: classic_conditions
|
||||
type: math
|
||||
noDataState: Alerting
|
||||
execErrState: Alerting
|
||||
for: 5m
|
||||
for: 15m
|
||||
annotations:
|
||||
summary: Watcher {{ index $labels "instance" }} of group {{ index $labels "job" }} is falling behind external head by {{ index $values "diff" }}
|
||||
isPaused: false
|
||||
@@ -363,29 +363,29 @@ groups:
|
||||
conditions:
|
||||
- evaluator:
|
||||
params:
|
||||
- 15
|
||||
- 0
|
||||
- 0
|
||||
type: gt
|
||||
operator:
|
||||
type: when
|
||||
type: and
|
||||
query:
|
||||
params:
|
||||
- diff
|
||||
params: []
|
||||
reducer:
|
||||
params: []
|
||||
type: last
|
||||
type: avg
|
||||
type: query
|
||||
datasource:
|
||||
name: Expression
|
||||
type: __expr__
|
||||
uid: __expr__
|
||||
expression: ""
|
||||
hide: false
|
||||
expression: ${diff} >= 16
|
||||
intervalMs: 1000
|
||||
maxDataPoints: 43200
|
||||
refId: condition
|
||||
type: classic_conditions
|
||||
type: math
|
||||
noDataState: Alerting
|
||||
execErrState: Alerting
|
||||
for: 5m
|
||||
for: 15m
|
||||
annotations:
|
||||
summary: Watcher {{ index $labels "instance" }} of group {{ index $labels "job" }} is falling behind external head by {{ index $values "diff" }}
|
||||
isPaused: false
|
||||
@@ -439,29 +439,29 @@ groups:
|
||||
conditions:
|
||||
- evaluator:
|
||||
params:
|
||||
- 15
|
||||
- 0
|
||||
- 0
|
||||
type: gt
|
||||
operator:
|
||||
type: when
|
||||
type: and
|
||||
query:
|
||||
params:
|
||||
- diff
|
||||
params: []
|
||||
reducer:
|
||||
params: []
|
||||
type: last
|
||||
type: avg
|
||||
type: query
|
||||
datasource:
|
||||
name: Expression
|
||||
type: __expr__
|
||||
uid: __expr__
|
||||
expression: ""
|
||||
hide: false
|
||||
expression: ${diff} >= 16
|
||||
intervalMs: 1000
|
||||
maxDataPoints: 43200
|
||||
refId: condition
|
||||
type: classic_conditions
|
||||
type: math
|
||||
noDataState: Alerting
|
||||
execErrState: Alerting
|
||||
for: 5m
|
||||
for: 15m
|
||||
annotations:
|
||||
summary: Watcher {{ index $labels "instance" }} of group {{ index $labels "job" }} is falling behind external head by {{ index $values "diff" }}
|
||||
isPaused: false
|
||||
@@ -515,29 +515,29 @@ groups:
|
||||
conditions:
|
||||
- evaluator:
|
||||
params:
|
||||
- 15
|
||||
- 0
|
||||
- 0
|
||||
type: gt
|
||||
operator:
|
||||
type: when
|
||||
type: and
|
||||
query:
|
||||
params:
|
||||
- diff
|
||||
params: []
|
||||
reducer:
|
||||
params: []
|
||||
type: last
|
||||
type: avg
|
||||
type: query
|
||||
datasource:
|
||||
name: Expression
|
||||
type: __expr__
|
||||
uid: __expr__
|
||||
expression: ""
|
||||
hide: false
|
||||
expression: ${diff} >= 16
|
||||
intervalMs: 1000
|
||||
maxDataPoints: 43200
|
||||
refId: condition
|
||||
type: classic_conditions
|
||||
type: math
|
||||
noDataState: Alerting
|
||||
execErrState: Alerting
|
||||
for: 5m
|
||||
for: 15m
|
||||
annotations:
|
||||
summary: Watcher {{ index $labels "instance" }} of group {{ index $labels "job" }} is falling behind external head by {{ index $values "diff" }}
|
||||
isPaused: false
|
||||
@@ -591,29 +591,29 @@ groups:
|
||||
conditions:
|
||||
- evaluator:
|
||||
params:
|
||||
- 15
|
||||
- 0
|
||||
- 0
|
||||
type: gt
|
||||
operator:
|
||||
type: when
|
||||
type: and
|
||||
query:
|
||||
params:
|
||||
- diff
|
||||
params: []
|
||||
reducer:
|
||||
params: []
|
||||
type: last
|
||||
type: avg
|
||||
type: query
|
||||
datasource:
|
||||
name: Expression
|
||||
type: __expr__
|
||||
uid: __expr__
|
||||
expression: ""
|
||||
hide: false
|
||||
expression: ${diff} >= 16
|
||||
intervalMs: 1000
|
||||
maxDataPoints: 43200
|
||||
refId: condition
|
||||
type: classic_conditions
|
||||
type: math
|
||||
noDataState: Alerting
|
||||
execErrState: Alerting
|
||||
for: 5m
|
||||
for: 15m
|
||||
annotations:
|
||||
summary: Watcher {{ index $labels "instance" }} of group {{ index $labels "job" }} is falling behind external head by {{ index $values "diff" }}
|
||||
isPaused: false
|
||||
@@ -669,29 +669,29 @@ groups:
|
||||
conditions:
|
||||
- evaluator:
|
||||
params:
|
||||
- 15
|
||||
- 0
|
||||
- 0
|
||||
type: gt
|
||||
operator:
|
||||
type: when
|
||||
type: and
|
||||
query:
|
||||
params:
|
||||
- diff
|
||||
params: []
|
||||
reducer:
|
||||
params: []
|
||||
type: last
|
||||
type: avg
|
||||
type: query
|
||||
datasource:
|
||||
name: Expression
|
||||
type: __expr__
|
||||
uid: __expr__
|
||||
expression: ""
|
||||
hide: false
|
||||
expression: ${diff} >= 16
|
||||
intervalMs: 1000
|
||||
maxDataPoints: 43200
|
||||
refId: condition
|
||||
type: classic_conditions
|
||||
type: math
|
||||
noDataState: Alerting
|
||||
execErrState: Alerting
|
||||
for: 5m
|
||||
for: 15m
|
||||
annotations:
|
||||
summary: Watcher {{ index $labels "instance" }} of group {{ index $labels "job" }} is falling behind external head by {{ index $values "diff" }}
|
||||
isPaused: false
|
||||
@@ -745,29 +745,29 @@ groups:
|
||||
conditions:
|
||||
- evaluator:
|
||||
params:
|
||||
- 15
|
||||
- 0
|
||||
- 0
|
||||
type: gt
|
||||
operator:
|
||||
type: when
|
||||
type: and
|
||||
query:
|
||||
params:
|
||||
- diff
|
||||
params: []
|
||||
reducer:
|
||||
params: []
|
||||
type: last
|
||||
type: avg
|
||||
type: query
|
||||
datasource:
|
||||
name: Expression
|
||||
type: __expr__
|
||||
uid: __expr__
|
||||
expression: ""
|
||||
hide: false
|
||||
expression: ${diff} >= 16
|
||||
intervalMs: 1000
|
||||
maxDataPoints: 43200
|
||||
refId: condition
|
||||
type: classic_conditions
|
||||
type: math
|
||||
noDataState: Alerting
|
||||
execErrState: Alerting
|
||||
for: 5m
|
||||
for: 15m
|
||||
annotations:
|
||||
summary: Watcher {{ index $labels "instance" }} of group {{ index $labels "job" }} is falling behind external head by {{ index $values "diff" }}
|
||||
isPaused: false
|
||||
@@ -823,29 +823,29 @@ groups:
|
||||
conditions:
|
||||
- evaluator:
|
||||
params:
|
||||
- 15
|
||||
- 0
|
||||
- 0
|
||||
type: gt
|
||||
operator:
|
||||
type: when
|
||||
type: and
|
||||
query:
|
||||
params:
|
||||
- diff
|
||||
params: []
|
||||
reducer:
|
||||
params: []
|
||||
type: last
|
||||
type: avg
|
||||
type: query
|
||||
datasource:
|
||||
name: Expression
|
||||
type: __expr__
|
||||
uid: __expr__
|
||||
expression: ""
|
||||
hide: false
|
||||
expression: ${diff} >= 16
|
||||
intervalMs: 1000
|
||||
maxDataPoints: 43200
|
||||
refId: condition
|
||||
type: classic_conditions
|
||||
type: math
|
||||
noDataState: Alerting
|
||||
execErrState: Alerting
|
||||
for: 5m
|
||||
for: 15m
|
||||
annotations:
|
||||
summary: Watcher {{ index $labels "instance" }} of group {{ index $labels "job" }} is falling behind external head by {{ index $values "diff" }}
|
||||
isPaused: false
|
||||
|
||||
@@ -109,6 +109,10 @@ else
|
||||
OTHER_OPTS="--miner.threads=1"
|
||||
fi
|
||||
|
||||
if [ "$CERC_ALLOW_UNPROTECTED_TXS" == "true" ]; then
|
||||
OTHER_OPTS+=" --rpc.allow-unprotected-txs"
|
||||
fi
|
||||
|
||||
$START_CMD \
|
||||
--datadir="${CERC_ETH_DATADIR}" \
|
||||
--bootnodes="${ENODE}" \
|
||||
|
||||
@@ -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-container:local -f ${SCRIPT_DIR}/Dockerfile ${build_command_args} $SCRIPT_DIR
|
||||
docker build -t cerc/test-container:local -f ${SCRIPT_DIR}/Dockerfile ${build_command_args} $SCRIPT_DIR
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
# fixturenet-plugeth
|
||||
|
||||
A variation of `fixturenet-eth` that uses `plugeth` instead of `go-ethereum`.
|
||||
|
||||
See `stacks/fixturenet-eth/README.md` for more information.
|
||||
|
||||
## Containers
|
||||
|
||||
* cerc/lighthouse
|
||||
* cerc/fixturenet-eth-plugeth
|
||||
* cerc/fixturenet-eth-lighthouse
|
||||
|
||||
## Deploy the stack
|
||||
|
||||
```bash
|
||||
laconic-so --stack fixturenet-plugeth setup-repositories
|
||||
laconic-so --stack fixturenet-plugeth build-containers
|
||||
laconic-so --stack fixturenet-plugeth deploy up
|
||||
```
|
||||
@@ -0,0 +1,17 @@
|
||||
version: "1.0"
|
||||
name: fixturenet-plugeth
|
||||
description: "Plugeth Ethereum Fixturenet"
|
||||
repos:
|
||||
- git.vdb.to/cerc-io/plugeth@statediff
|
||||
- git.vdb.to/cerc-io/plugeth-statediff
|
||||
- git.vdb.to/cerc-io/lighthouse
|
||||
containers:
|
||||
- cerc/plugeth-statediff
|
||||
- cerc/plugeth
|
||||
- cerc/fixturenet-eth-genesis
|
||||
- cerc/fixturenet-plugeth-plugeth
|
||||
- cerc/lighthouse
|
||||
- cerc/lighthouse-cli
|
||||
- cerc/fixturenet-eth-lighthouse
|
||||
pods:
|
||||
- fixturenet-plugeth
|
||||
@@ -76,6 +76,19 @@ export ETH_RPC_PORT=
|
||||
# The etherum network(s) graph-node will connect to
|
||||
# Set this to a space-separated list of the networks where each entry has the form NAME:URL
|
||||
export ETH_NETWORKS=
|
||||
|
||||
# Optional:
|
||||
|
||||
# Timeout for ETH RPC requests in seconds (default: 180s)
|
||||
export GRAPH_ETHEREUM_JSON_RPC_TIMEOUT=
|
||||
|
||||
# Number of times to retry ETH RPC requests (default: 10)
|
||||
export GRAPH_ETHEREUM_REQUEST_RETRIES=
|
||||
|
||||
# Maximum number of blocks to scan for triggers in each request (default: 2000)
|
||||
export GRAPH_ETHEREUM_MAX_BLOCK_RANGE_SIZE=
|
||||
|
||||
# Ref: https://git.vdb.to/cerc-io/graph-node/src/branch/master/docs/environment-variables.md
|
||||
```
|
||||
|
||||
Example env file:
|
||||
@@ -85,6 +98,10 @@ export ETH_RPC_HOST=filecoin.chainup.net
|
||||
export ETH_RPC_PORT=443
|
||||
|
||||
export ETH_NETWORKS=filecoin:https://filecoin.chainup.net/rpc/v1
|
||||
|
||||
export GRAPH_ETHEREUM_JSON_RPC_TIMEOUT=360
|
||||
export GRAPH_ETHEREUM_REQUEST_RETRIES=5
|
||||
export GRAPH_ETHEREUM_MAX_BLOCK_RANGE_SIZE=50
|
||||
```
|
||||
|
||||
Set the environment variables:
|
||||
|
||||
@@ -123,9 +123,8 @@ laconic-so --stack monitoring deploy create --spec-file monitoring-spec.yml --de
|
||||
```yml
|
||||
...
|
||||
- job_name: laconicd
|
||||
...
|
||||
static_configs:
|
||||
- targets: ['example-host:1317']
|
||||
static_configs:
|
||||
- targets: ['example-host:1317']
|
||||
...
|
||||
```
|
||||
|
||||
|
||||
@@ -44,18 +44,13 @@ Add the following scrape configs to prometheus config file (`monitoring-watchers
|
||||
- job_name: 'blackbox'
|
||||
...
|
||||
static_configs:
|
||||
- targets: [<AZIMUTH_GATEWAY_GQL_ENDPOINT>]
|
||||
labels:
|
||||
# Add destination label for pre-configured alerts
|
||||
destination: 'azimuth_gateway'
|
||||
- targets: [<LACONICD_GQL_ENDPOINT>]
|
||||
labels:
|
||||
destination: 'laconicd_gql'
|
||||
- targets:
|
||||
- <AZIMUTH_GATEWAY_GQL_ENDPOINT>
|
||||
- <LACONICD_GQL_ENDPOINT>
|
||||
...
|
||||
- job_name: laconicd
|
||||
...
|
||||
static_configs:
|
||||
- targets: ['LACONICD_REST_HOST:LACONICD_REST_PORT']
|
||||
static_configs:
|
||||
- targets: ['LACONICD_REST_HOST:LACONICD_REST_PORT']
|
||||
...
|
||||
- job_name: azimuth
|
||||
scrape_interval: 10s
|
||||
@@ -124,12 +119,10 @@ Add scrape config as done above for any additional watcher to add it to the Watc
|
||||
|
||||
### Grafana alerts config
|
||||
|
||||
Place the pre-configured watcher and blackbox endpoint alerts rules in Grafana provisioning directory:
|
||||
Place the pre-configured watcher alerts rules in Grafana provisioning directory:
|
||||
|
||||
```bash
|
||||
cp monitoring-watchers-deployment/config/monitoring/watcher-alert-rules.yml monitoring-watchers-deployment/config/monitoring/grafana/provisioning/alerting/
|
||||
|
||||
cp monitoring-watchers-deployment/config/monitoring/blackbox-alert-rules.yml monitoring-watchers-deployment/config/monitoring/grafana/provisioning/alerting/
|
||||
```
|
||||
|
||||
Update the alerting contact points config (`monitoring-watchers-deployment/config/monitoring/grafana/provisioning/alerting/contactpoints.yml`) with desired contact points
|
||||
@@ -142,7 +135,7 @@ Add corresponding routes to the notification policies config (`monitoring-watche
|
||||
- receiver: SlackNotifier
|
||||
object_matchers:
|
||||
# Add matchers below
|
||||
- ['grafana_folder', '=~', 'WatcherAlerts|BlackboxAlerts']
|
||||
- ['grafana_folder', '=', 'WatcherAlerts']
|
||||
```
|
||||
|
||||
### Env
|
||||
|
||||
@@ -2,10 +2,10 @@ version: "1.0"
|
||||
name: webapp-deployer-backend
|
||||
description: "Deployer for webapps"
|
||||
repos:
|
||||
- git.vdb.to/telackey/webapp-deployment-status-api
|
||||
- git.vdb.to/cerc-io/webapp-deployment-status-api
|
||||
containers:
|
||||
- cerc/webapp-deployer-backend
|
||||
pods:
|
||||
- name: webapp-deployer-backend
|
||||
repository: git.vdb.to/telackey/webapp-deployment-status-api
|
||||
repository: git.vdb.to/cerc-io/webapp-deployment-status-api
|
||||
path: ./
|
||||
|
||||
@@ -27,6 +27,7 @@ from pathlib import Path
|
||||
from stack_orchestrator import constants
|
||||
from stack_orchestrator.opts import opts
|
||||
from stack_orchestrator.util import include_exclude_check, get_parsed_stack_config, global_options2, get_dev_root_path
|
||||
from stack_orchestrator.util import resolve_compose_file
|
||||
from stack_orchestrator.deploy.deployer import Deployer, DeployerException
|
||||
from stack_orchestrator.deploy.deployer_factory import getDeployer
|
||||
from stack_orchestrator.deploy.deploy_types import ClusterContext, DeployCommandContext
|
||||
@@ -324,7 +325,10 @@ def _make_cluster_context(ctx, stack, include, exclude, cluster, env_file):
|
||||
pod_path = pod["path"]
|
||||
if include_exclude_check(pod_name, include, exclude):
|
||||
if pod_repository is None or pod_repository == "internal":
|
||||
compose_file_name = os.path.join(compose_dir, f"docker-compose-{pod_path}.yml")
|
||||
if deployment:
|
||||
compose_file_name = os.path.join(compose_dir, f"docker-compose-{pod_path}.yml")
|
||||
else:
|
||||
compose_file_name = resolve_compose_file(stack, pod_name)
|
||||
else:
|
||||
if deployment:
|
||||
compose_file_name = os.path.join(compose_dir, f"docker-compose-{pod_name}.yml")
|
||||
@@ -336,6 +340,7 @@ def _make_cluster_context(ctx, stack, include, exclude, cluster, env_file):
|
||||
if pod_post_start_command is not None:
|
||||
post_start_commands.append(os.path.join(script_dir, pod_post_start_command))
|
||||
else:
|
||||
# TODO: fix this code for external stack with scripts
|
||||
pod_root_dir = os.path.join(dev_root_path, pod_repository.split("/")[-1], pod["path"])
|
||||
compose_file_name = os.path.join(pod_root_dir, f"docker-compose-{pod_name}.yml")
|
||||
pod_pre_start_command = pod.get("pre_start_command")
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
import os
|
||||
from typing import List, Any
|
||||
from stack_orchestrator.deploy.deploy_types import DeployCommandContext, VolumeMapping
|
||||
from stack_orchestrator.util import get_parsed_stack_config, get_yaml, get_compose_file_dir, get_pod_list
|
||||
from stack_orchestrator.util import get_parsed_stack_config, get_yaml, get_pod_list, resolve_compose_file
|
||||
from stack_orchestrator.opts import opts
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ def _container_image_from_service(stack: str, service: str):
|
||||
pods = get_pod_list(parsed_stack)
|
||||
yaml = get_yaml()
|
||||
for pod in pods:
|
||||
pod_file_path = os.path.join(get_compose_file_dir(), f"docker-compose-{pod}.yml")
|
||||
pod_file_path = resolve_compose_file(stack, pod)
|
||||
parsed_pod_file = yaml.load(open(pod_file_path, "r"))
|
||||
if "services" in parsed_pod_file:
|
||||
services = parsed_pod_file["services"]
|
||||
|
||||
@@ -26,7 +26,8 @@ from stack_orchestrator import constants
|
||||
from stack_orchestrator.opts import opts
|
||||
from stack_orchestrator.util import (get_stack_file_path, get_parsed_deployment_spec, get_parsed_stack_config,
|
||||
global_options, get_yaml, get_pod_list, get_pod_file_path, pod_has_scripts,
|
||||
get_pod_script_paths, get_plugin_code_paths, error_exit, env_var_map_from_file)
|
||||
get_pod_script_paths, get_plugin_code_paths, error_exit, env_var_map_from_file,
|
||||
resolve_config_dir)
|
||||
from stack_orchestrator.deploy.spec import Spec
|
||||
from stack_orchestrator.deploy.deploy_types import LaconicStackSetupCommand
|
||||
from stack_orchestrator.deploy.deployer_factory import getDeployerConfigGenerator
|
||||
@@ -43,7 +44,7 @@ def _get_ports(stack):
|
||||
pods = get_pod_list(parsed_stack)
|
||||
yaml = get_yaml()
|
||||
for pod in pods:
|
||||
pod_file_path = get_pod_file_path(parsed_stack, pod)
|
||||
pod_file_path = get_pod_file_path(stack, parsed_stack, pod)
|
||||
parsed_pod_file = yaml.load(open(pod_file_path, "r"))
|
||||
if "services" in parsed_pod_file:
|
||||
for svc_name, svc in parsed_pod_file["services"].items():
|
||||
@@ -79,7 +80,7 @@ def _get_named_volumes(stack):
|
||||
return ret
|
||||
|
||||
for pod in pods:
|
||||
pod_file_path = get_pod_file_path(parsed_stack, pod)
|
||||
pod_file_path = get_pod_file_path(stack, parsed_stack, pod)
|
||||
parsed_pod_file = yaml.load(open(pod_file_path, "r"))
|
||||
if "volumes" in parsed_pod_file:
|
||||
volumes = parsed_pod_file["volumes"]
|
||||
@@ -480,10 +481,9 @@ def create_operation(deployment_command_context, spec_file, deployment_dir, netw
|
||||
os.mkdir(destination_compose_dir)
|
||||
destination_pods_dir = deployment_dir_path.joinpath("pods")
|
||||
os.mkdir(destination_pods_dir)
|
||||
data_dir = Path(__file__).absolute().parent.parent.joinpath("data")
|
||||
yaml = get_yaml()
|
||||
for pod in pods:
|
||||
pod_file_path = get_pod_file_path(parsed_stack, pod)
|
||||
pod_file_path = get_pod_file_path(stack_name, parsed_stack, pod)
|
||||
parsed_pod_file = yaml.load(open(pod_file_path, "r"))
|
||||
extra_config_dirs = _find_extra_config_dirs(parsed_pod_file, pod)
|
||||
destination_pod_dir = destination_pods_dir.joinpath(pod)
|
||||
@@ -497,7 +497,7 @@ def create_operation(deployment_command_context, spec_file, deployment_dir, netw
|
||||
config_dirs = {pod}
|
||||
config_dirs = config_dirs.union(extra_config_dirs)
|
||||
for config_dir in config_dirs:
|
||||
source_config_dir = data_dir.joinpath("config", config_dir)
|
||||
source_config_dir = resolve_config_dir(stack_name, config_dir)
|
||||
if os.path.exists(source_config_dir):
|
||||
destination_config_dir = deployment_dir_path.joinpath("config", config_dir)
|
||||
# If the same config dir appears in multiple pods, it may already have been copied
|
||||
|
||||
@@ -39,11 +39,12 @@ def process_app_deployment_request(
|
||||
app_deployment_request,
|
||||
deployment_record_namespace,
|
||||
dns_record_namespace,
|
||||
dns_suffix,
|
||||
default_dns_suffix,
|
||||
deployment_parent_dir,
|
||||
kube_config,
|
||||
image_registry,
|
||||
force_rebuild,
|
||||
fqdn_policy,
|
||||
logger
|
||||
):
|
||||
logger.log("BEGIN - process_app_deployment_request")
|
||||
@@ -56,14 +57,15 @@ def process_app_deployment_request(
|
||||
requested_name = hostname_for_deployment_request(app_deployment_request, laconic)
|
||||
logger.log(f"Determined requested name: {requested_name}")
|
||||
|
||||
# HACK
|
||||
if "." in requested_name:
|
||||
raise Exception("Only unqualified hostnames allowed at this time.")
|
||||
|
||||
fqdn = f"{requested_name}.{dns_suffix}"
|
||||
if "allow" == fqdn_policy or "preexisting" == fqdn_policy:
|
||||
fqdn = requested_name
|
||||
else:
|
||||
raise Exception(f"{requested_name} is invalid: only unqualified hostnames are allowed.")
|
||||
else:
|
||||
fqdn = f"{requested_name}.{default_dns_suffix}"
|
||||
|
||||
# 3. check ownership of existing dnsrecord vs this request
|
||||
# TODO: Support foreign DNS
|
||||
dns_crn = f"{dns_record_namespace}/{fqdn}"
|
||||
dns_record = laconic.get_record(dns_crn)
|
||||
if dns_record:
|
||||
@@ -75,7 +77,9 @@ def process_app_deployment_request(
|
||||
logger.log(f"Matched DnsRecord ownership: {matched_owner}")
|
||||
else:
|
||||
raise Exception("Unable to confirm ownership of DnsRecord %s for request %s" %
|
||||
(dns_record.id, app_deployment_request.id))
|
||||
(dns_crn, app_deployment_request.id))
|
||||
elif "preexisting" == fqdn_policy:
|
||||
raise Exception(f"No pre-existing DnsRecord {dns_crn} could be found for request {app_deployment_request.id}.")
|
||||
|
||||
# 4. get build and runtime config from request
|
||||
env_filename = None
|
||||
@@ -191,6 +195,7 @@ def dump_known_requests(filename, requests, status="SEEN"):
|
||||
@click.option("--state-file", help="File to store state about previously seen requests.")
|
||||
@click.option("--only-update-state", help="Only update the state file, don't process any requests anything.", is_flag=True)
|
||||
@click.option("--dns-suffix", help="DNS domain to use eg, laconic.servesthe.world")
|
||||
@click.option("--fqdn-policy", help="How to handle requests with an FQDN: prohibit, allow, preexisting", default="prohibit")
|
||||
@click.option("--record-namespace-dns", help="eg, crn://laconic/dns")
|
||||
@click.option("--record-namespace-deployments", help="eg, crn://laconic/deployments")
|
||||
@click.option("--dry-run", help="Don't do anything, just report what would be done.", is_flag=True)
|
||||
@@ -201,7 +206,7 @@ def dump_known_requests(filename, requests, status="SEEN"):
|
||||
@click.pass_context
|
||||
def command(ctx, kube_config, laconic_config, image_registry, deployment_parent_dir, # noqa: C901
|
||||
request_id, discover, state_file, only_update_state,
|
||||
dns_suffix, record_namespace_dns, record_namespace_deployments, dry_run,
|
||||
dns_suffix, fqdn_policy, record_namespace_dns, record_namespace_deployments, dry_run,
|
||||
include_tags, exclude_tags, force_rebuild, log_dir):
|
||||
if request_id and discover:
|
||||
print("Cannot specify both --request-id and --discover", file=sys.stderr)
|
||||
@@ -220,6 +225,10 @@ def command(ctx, kube_config, laconic_config, image_registry, deployment_parent_
|
||||
print("--dns-suffix, --record-namespace-dns, and --record-namespace-deployments are all required", file=sys.stderr)
|
||||
sys.exit(2)
|
||||
|
||||
if fqdn_policy not in ["prohibit", "allow", "preexisting"]:
|
||||
print("--fqdn-policy must be one of 'prohibit', 'allow', or 'preexisting'", file=sys.stderr)
|
||||
sys.exit(2)
|
||||
|
||||
# Split CSV and clean up values.
|
||||
include_tags = [tag.strip() for tag in include_tags.split(",") if tag]
|
||||
exclude_tags = [tag.strip() for tag in exclude_tags.split(",") if tag]
|
||||
@@ -247,7 +256,10 @@ def command(ctx, kube_config, laconic_config, image_registry, deployment_parent_
|
||||
requests_by_name = {}
|
||||
skipped_by_name = {}
|
||||
for r in requests:
|
||||
# TODO: Do this _after_ filtering deployments and cancellations to minimize round trips.
|
||||
if r.id in previous_requests and previous_requests[r.id].get("status", "") != "RETRY":
|
||||
print(f"Skipping request {r.id}, we've already seen it.")
|
||||
continue
|
||||
|
||||
app = laconic.get_record(r.attributes.application)
|
||||
if not app:
|
||||
print("Skipping request %s, cannot locate app." % r.id)
|
||||
@@ -334,6 +346,7 @@ def command(ctx, kube_config, laconic_config, image_registry, deployment_parent_
|
||||
kube_config,
|
||||
image_registry,
|
||||
force_rebuild,
|
||||
fqdn_policy,
|
||||
logger
|
||||
)
|
||||
status = "DEPLOYED"
|
||||
|
||||
@@ -17,6 +17,7 @@ import click
|
||||
|
||||
from stack_orchestrator.command_types import CommandOptions
|
||||
from stack_orchestrator.repos import setup_repositories
|
||||
from stack_orchestrator.repos import fetch_stack
|
||||
from stack_orchestrator.build import build_containers, fetch_containers
|
||||
from stack_orchestrator.build import build_npms
|
||||
from stack_orchestrator.build import build_webapp
|
||||
@@ -50,6 +51,7 @@ def cli(ctx, stack, quiet, verbose, dry_run, local_stack, debug, continue_on_err
|
||||
ctx.obj = command_options
|
||||
|
||||
|
||||
cli.add_command(fetch_stack.command, "fetch-stack")
|
||||
cli.add_command(setup_repositories.command, "setup-repositories")
|
||||
cli.add_command(build_containers.command, "build-containers")
|
||||
cli.add_command(fetch_containers.command, "fetch-containers")
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
# Copyright © 2022, 2023 Vulcanize
|
||||
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http:#www.gnu.org/licenses/>.
|
||||
|
||||
# env vars:
|
||||
# CERC_REPO_BASE_DIR defaults to ~/cerc
|
||||
|
||||
|
||||
import click
|
||||
import os
|
||||
|
||||
from decouple import config
|
||||
from git import exc
|
||||
|
||||
from stack_orchestrator.opts import opts
|
||||
from stack_orchestrator.repos.setup_repositories import process_repo
|
||||
from stack_orchestrator.util import error_exit
|
||||
|
||||
|
||||
@click.command()
|
||||
@click.argument('stack-locator')
|
||||
@click.option('--git-ssh', is_flag=True, default=False)
|
||||
@click.option('--check-only', is_flag=True, default=False)
|
||||
@click.option('--pull', is_flag=True, default=False)
|
||||
@click.pass_context
|
||||
def command(ctx, stack_locator, git_ssh, check_only, pull):
|
||||
'''optionally resolve then git clone a repository containing one or more stack definitions'''
|
||||
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}")
|
||||
try:
|
||||
process_repo(pull, check_only, git_ssh, dev_root_path, None, stack_locator)
|
||||
except exc.GitCommandError as error:
|
||||
error_exit(f"\n******* git command returned error exit status:\n{error}")
|
||||
@@ -26,6 +26,7 @@ import importlib.resources
|
||||
from pathlib import Path
|
||||
import yaml
|
||||
from stack_orchestrator.constants import stack_file_name
|
||||
from stack_orchestrator.opts import opts
|
||||
from stack_orchestrator.util import include_exclude_check, stack_is_external, error_exit, warn_exit
|
||||
|
||||
|
||||
@@ -87,8 +88,8 @@ def _get_repo_current_branch_or_tag(full_filesystem_repo_path):
|
||||
|
||||
|
||||
# TODO: fix the messy arg list here
|
||||
def process_repo(verbose, quiet, dry_run, pull, check_only, git_ssh, dev_root_path, branches_array, fully_qualified_repo):
|
||||
if verbose:
|
||||
def process_repo(pull, check_only, git_ssh, dev_root_path, branches_array, fully_qualified_repo):
|
||||
if opts.o.verbose:
|
||||
print(f"Processing repo: {fully_qualified_repo}")
|
||||
repo_host, repo_path, repo_branch = host_and_path_for_repo(fully_qualified_repo)
|
||||
git_ssh_prefix = f"git@{repo_host}:"
|
||||
@@ -100,7 +101,7 @@ def process_repo(verbose, quiet, dry_run, pull, check_only, git_ssh, dev_root_pa
|
||||
(current_repo_branch_or_tag, is_branch) = _get_repo_current_branch_or_tag(
|
||||
full_filesystem_repo_path
|
||||
) if is_present else (None, None)
|
||||
if not quiet:
|
||||
if not opts.o.quiet:
|
||||
present_text = f"already exists active {'branch' if is_branch else 'tag'}: {current_repo_branch_or_tag}" if is_present \
|
||||
else 'Needs to be fetched'
|
||||
print(f"Checking: {full_filesystem_repo_path}: {present_text}")
|
||||
@@ -111,25 +112,25 @@ def process_repo(verbose, quiet, dry_run, pull, check_only, git_ssh, dev_root_pa
|
||||
sys.exit(1)
|
||||
else:
|
||||
if pull:
|
||||
if verbose:
|
||||
if opts.o.verbose:
|
||||
print(f"Running git pull for {full_filesystem_repo_path}")
|
||||
if not check_only:
|
||||
if is_branch:
|
||||
git_repo = git.Repo(full_filesystem_repo_path)
|
||||
origin = git_repo.remotes.origin
|
||||
origin.pull(progress=None if quiet else GitProgress())
|
||||
origin.pull(progress=None if opts.o.quiet else GitProgress())
|
||||
else:
|
||||
print("skipping pull because this repo checked out a tag")
|
||||
else:
|
||||
print("(git pull skipped)")
|
||||
if not is_present:
|
||||
# Clone
|
||||
if verbose:
|
||||
if opts.o.verbose:
|
||||
print(f'Running git clone for {full_github_repo_path} into {full_filesystem_repo_path}')
|
||||
if not dry_run:
|
||||
if not opts.o.dry_run:
|
||||
git.Repo.clone_from(full_github_repo_path,
|
||||
full_filesystem_repo_path,
|
||||
progress=None if quiet else GitProgress())
|
||||
progress=None if opts.o.quiet else GitProgress())
|
||||
else:
|
||||
print("(git clone skipped)")
|
||||
# Checkout the requested branch, if one was specified
|
||||
@@ -150,13 +151,13 @@ def process_repo(verbose, quiet, dry_run, pull, check_only, git_ssh, dev_root_pa
|
||||
current_repo_branch_or_tag and (
|
||||
current_repo_branch_or_tag != branch_to_checkout)
|
||||
):
|
||||
if not quiet:
|
||||
if not opts.o.quiet:
|
||||
print(f"switching to branch {branch_to_checkout} in repo {repo_path}")
|
||||
git_repo = git.Repo(full_filesystem_repo_path)
|
||||
# git checkout works for both branches and tags
|
||||
git_repo.git.checkout(branch_to_checkout)
|
||||
else:
|
||||
if verbose:
|
||||
if opts.o.verbose:
|
||||
print(f"repo {repo_path} is already on branch/tag {branch_to_checkout}")
|
||||
|
||||
|
||||
@@ -182,36 +183,18 @@ def parse_branches(branches_string):
|
||||
@click.option('--check-only', is_flag=True, default=False)
|
||||
@click.option('--pull', is_flag=True, default=False)
|
||||
@click.option("--branches", help="override branches for repositories")
|
||||
@click.option('--branches-file', help="checkout branches specified in this file")
|
||||
@click.pass_context
|
||||
def command(ctx, include, exclude, git_ssh, check_only, pull, branches, branches_file):
|
||||
def command(ctx, include, exclude, git_ssh, check_only, pull, branches):
|
||||
'''git clone the set of repositories required to build the complete system from source'''
|
||||
|
||||
quiet = ctx.obj.quiet
|
||||
verbose = ctx.obj.verbose
|
||||
dry_run = ctx.obj.dry_run
|
||||
stack = ctx.obj.stack
|
||||
quiet = opts.o.quiet
|
||||
verbose = opts.o.verbose
|
||||
stack = opts.o.stack
|
||||
|
||||
branches_array = []
|
||||
|
||||
# TODO: branches file needs to be re-worked in the context of stacks
|
||||
if branches_file:
|
||||
if branches:
|
||||
print("Error: can't specify both --branches and --branches-file")
|
||||
sys.exit(1)
|
||||
else:
|
||||
if verbose:
|
||||
print(f"loading branches from: {branches_file}")
|
||||
with open(branches_file) as branches_file_open:
|
||||
branches_array = branches_file_open.read().splitlines()
|
||||
|
||||
print(f"branches: {branches}")
|
||||
if branches:
|
||||
if branches_file:
|
||||
print("Error: can't specify both --branches and --branches-file")
|
||||
sys.exit(1)
|
||||
else:
|
||||
branches_array = parse_branches(branches)
|
||||
branches_array = parse_branches(branches)
|
||||
|
||||
if branches_array and verbose:
|
||||
print(f"Branches are: {branches_array}")
|
||||
@@ -271,7 +254,6 @@ def command(ctx, include, exclude, git_ssh, check_only, pull, branches, branches
|
||||
|
||||
for repo in repos:
|
||||
try:
|
||||
process_repo(verbose, quiet, dry_run, pull, check_only, git_ssh, dev_root_path, branches_array, repo)
|
||||
process_repo(pull, check_only, git_ssh, dev_root_path, branches_array, repo)
|
||||
except git.exc.GitCommandError as error:
|
||||
print(f"\n******* git command returned error exit status:\n{error}")
|
||||
sys.exit(1)
|
||||
error_exit(f"\n******* git command returned error exit status:\n{error}")
|
||||
|
||||
@@ -94,10 +94,38 @@ def get_plugin_code_paths(stack) -> List[Path]:
|
||||
return list(result)
|
||||
|
||||
|
||||
def get_pod_file_path(parsed_stack, pod_name: str):
|
||||
# # Find a config directory, looking first in any external stack
|
||||
# and if not found there, internally
|
||||
def resolve_config_dir(stack, config_dir_name: str):
|
||||
if stack_is_external(stack):
|
||||
# First try looking in the external stack for the compose file
|
||||
config_base = Path(stack).parent.parent.joinpath("config")
|
||||
proposed_dir = config_base.joinpath(config_dir_name)
|
||||
if proposed_dir.exists():
|
||||
return proposed_dir
|
||||
# If we don't find it fall through to the internal case
|
||||
config_base = get_internal_config_dir()
|
||||
return config_base.joinpath(config_dir_name)
|
||||
|
||||
|
||||
# Find a compose file, looking first in any external stack
|
||||
# and if not found there, internally
|
||||
def resolve_compose_file(stack, pod_name: str):
|
||||
if stack_is_external(stack):
|
||||
# First try looking in the external stack for the compose file
|
||||
compose_base = Path(stack).parent.parent.joinpath("compose")
|
||||
proposed_file = compose_base.joinpath(f"docker-compose-{pod_name}.yml")
|
||||
if proposed_file.exists():
|
||||
return proposed_file
|
||||
# If we don't find it fall through to the internal case
|
||||
compose_base = get_internal_compose_file_dir()
|
||||
return compose_base.joinpath(f"docker-compose-{pod_name}.yml")
|
||||
|
||||
|
||||
def get_pod_file_path(stack, parsed_stack, pod_name: str):
|
||||
pods = parsed_stack["pods"]
|
||||
if type(pods[0]) is str:
|
||||
result = os.path.join(get_compose_file_dir(), f"docker-compose-{pod_name}.yml")
|
||||
result = resolve_compose_file(stack, pod_name)
|
||||
else:
|
||||
for pod in pods:
|
||||
if pod["name"] == pod_name:
|
||||
@@ -131,7 +159,7 @@ def pod_has_scripts(parsed_stack, pod_name: str):
|
||||
return result
|
||||
|
||||
|
||||
def get_compose_file_dir():
|
||||
def get_internal_compose_file_dir():
|
||||
# TODO: refactor to use common code with deploy command
|
||||
# See: https://stackoverflow.com/questions/25389095/python-get-path-of-root-project-structure
|
||||
data_dir = Path(__file__).absolute().parent.joinpath("data")
|
||||
@@ -139,7 +167,7 @@ def get_compose_file_dir():
|
||||
return source_compose_dir
|
||||
|
||||
|
||||
def get_config_file_dir():
|
||||
def get_internal_config_dir():
|
||||
# TODO: refactor to use common code with deploy command
|
||||
data_dir = Path(__file__).absolute().parent.joinpath("data")
|
||||
source_config_dir = data_dir.joinpath("config")
|
||||
|
||||
Executable
+185
@@ -0,0 +1,185 @@
|
||||
#!/usr/bin/env bash
|
||||
set -e
|
||||
if [ -n "$CERC_SCRIPT_DEBUG" ]; then
|
||||
set -x
|
||||
fi
|
||||
# Dump environment variables for debugging
|
||||
echo "Environment variables:"
|
||||
env
|
||||
|
||||
if [ "$1" == "from-path" ]; then
|
||||
TEST_TARGET_SO="laconic-so"
|
||||
else
|
||||
TEST_TARGET_SO=$( ls -t1 ./package/laconic-so* | head -1 )
|
||||
fi
|
||||
|
||||
delete_cluster_exit () {
|
||||
$TEST_TARGET_SO deployment --dir $test_deployment_dir stop --delete-volumes
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Test basic stack-orchestrator deploy
|
||||
echo "Running stack-orchestrator external stack deploy test"
|
||||
# Set a non-default repo dir
|
||||
export CERC_REPO_BASE_DIR=~/stack-orchestrator-test/repo-base-dir
|
||||
echo "Testing this package: $TEST_TARGET_SO"
|
||||
echo "Test version command"
|
||||
reported_version_string=$( $TEST_TARGET_SO version )
|
||||
echo "Version reported is: ${reported_version_string}"
|
||||
echo "Cloning repositories into: $CERC_REPO_BASE_DIR"
|
||||
rm -rf $CERC_REPO_BASE_DIR
|
||||
mkdir -p $CERC_REPO_BASE_DIR
|
||||
# Clone the external test stack
|
||||
$TEST_TARGET_SO fetch-stack git.vdb.to/cerc-io/test-external-stack
|
||||
stack_name="$CERC_REPO_BASE_DIR/test-external-stack/stack-orchestrator/stacks/test-external-stack"
|
||||
TEST_TARGET_SO_STACK="$TEST_TARGET_SO --stack ${stack_name}"
|
||||
# Test bringing the test container up and down
|
||||
# with and without volume removal
|
||||
$TEST_TARGET_SO_STACK setup-repositories
|
||||
$TEST_TARGET_SO_STACK build-containers
|
||||
# Test deploy command execution
|
||||
$TEST_TARGET_SO_STACK deploy setup $CERC_REPO_BASE_DIR
|
||||
# Check that we now have the expected output directory
|
||||
container_output_dir=$CERC_REPO_BASE_DIR/container-output-dir
|
||||
if [ ! -d "$container_output_dir" ]; then
|
||||
echo "deploy setup test: output directory not present"
|
||||
echo "deploy setup test: FAILED"
|
||||
exit 1
|
||||
fi
|
||||
if [ ! -f "$container_output_dir/output-file" ]; then
|
||||
echo "deploy setup test: output file not present"
|
||||
echo "deploy setup test: FAILED"
|
||||
exit 1
|
||||
fi
|
||||
output_file_content=$(<$container_output_dir/output-file)
|
||||
if [ ! "$output_file_content" == "output-data" ]; then
|
||||
echo "deploy setup test: output file contents not correct"
|
||||
echo "deploy setup test: FAILED"
|
||||
exit 1
|
||||
fi
|
||||
# Check that we now have the expected output file
|
||||
$TEST_TARGET_SO_STACK deploy up
|
||||
# Test deploy port command
|
||||
deploy_port_output=$( $TEST_TARGET_SO_STACK deploy port test 80 )
|
||||
if [[ "$deploy_port_output" =~ ^0.0.0.0:[1-9][0-9]* ]]; then
|
||||
echo "Deploy port test: passed"
|
||||
else
|
||||
echo "Deploy port test: FAILED"
|
||||
exit 1
|
||||
fi
|
||||
$TEST_TARGET_SO_STACK deploy down
|
||||
# The next time we bring the container up the volume will be old (from the previous run above)
|
||||
$TEST_TARGET_SO_STACK deploy up
|
||||
log_output_1=$( $TEST_TARGET_SO_STACK deploy logs )
|
||||
if [[ "$log_output_1" == *"filesystem is old"* ]]; then
|
||||
echo "Retain volumes test: passed"
|
||||
else
|
||||
echo "Retain volumes test: FAILED"
|
||||
exit 1
|
||||
fi
|
||||
$TEST_TARGET_SO_STACK deploy down --delete-volumes
|
||||
# Now when we bring the container up the volume will be new again
|
||||
$TEST_TARGET_SO_STACK deploy up
|
||||
log_output_2=$( $TEST_TARGET_SO_STACK deploy logs )
|
||||
if [[ "$log_output_2" == *"filesystem is fresh"* ]]; then
|
||||
echo "Delete volumes test: passed"
|
||||
else
|
||||
echo "Delete volumes test: FAILED"
|
||||
exit 1
|
||||
fi
|
||||
$TEST_TARGET_SO_STACK deploy down --delete-volumes
|
||||
# Basic test of creating a deployment
|
||||
test_deployment_dir=$CERC_REPO_BASE_DIR/test-deployment-dir
|
||||
test_deployment_spec=$CERC_REPO_BASE_DIR/test-deployment-spec.yml
|
||||
$TEST_TARGET_SO_STACK deploy init --output $test_deployment_spec --config CERC_TEST_PARAM_1=PASSED,CERC_TEST_PARAM_3=FAST
|
||||
# Check the file now exists
|
||||
if [ ! -f "$test_deployment_spec" ]; then
|
||||
echo "deploy init test: spec file not present"
|
||||
echo "deploy init test: FAILED"
|
||||
exit 1
|
||||
fi
|
||||
echo "deploy init test: passed"
|
||||
$TEST_TARGET_SO_STACK deploy create --spec-file $test_deployment_spec --deployment-dir $test_deployment_dir
|
||||
# Check the deployment dir exists
|
||||
if [ ! -d "$test_deployment_dir" ]; then
|
||||
echo "deploy create test: deployment directory not present"
|
||||
echo "deploy create test: FAILED"
|
||||
exit 1
|
||||
fi
|
||||
echo "deploy create test: passed"
|
||||
# Check the file writted by the create command in the stack now exists
|
||||
if [ ! -f "$test_deployment_dir/create-file" ]; then
|
||||
echo "deploy create test: create output file not present"
|
||||
echo "deploy create test: FAILED"
|
||||
exit 1
|
||||
fi
|
||||
# And has the right content
|
||||
create_file_content=$(<$test_deployment_dir/create-file)
|
||||
if [ ! "$create_file_content" == "create-command-output-data" ]; then
|
||||
echo "deploy create test: create output file contents not correct"
|
||||
echo "deploy create test: FAILED"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Add a config file to be picked up by the ConfigMap before starting.
|
||||
echo "dbfc7a4d-44a7-416d-b5f3-29842cc47650" > $test_deployment_dir/data/test-config/test_config
|
||||
|
||||
echo "deploy create output file test: passed"
|
||||
# Try to start the deployment
|
||||
$TEST_TARGET_SO deployment --dir $test_deployment_dir start
|
||||
# Check logs command works
|
||||
log_output_3=$( $TEST_TARGET_SO deployment --dir $test_deployment_dir logs )
|
||||
if [[ "$log_output_3" == *"filesystem is fresh"* ]]; then
|
||||
echo "deployment logs test: passed"
|
||||
else
|
||||
echo "deployment logs test: FAILED"
|
||||
exit 1
|
||||
fi
|
||||
# Check the config variable CERC_TEST_PARAM_1 was passed correctly
|
||||
if [[ "$log_output_3" == *"Test-param-1: PASSED"* ]]; then
|
||||
echo "deployment config test: passed"
|
||||
else
|
||||
echo "deployment config test: FAILED"
|
||||
exit 1
|
||||
fi
|
||||
# Check the config variable CERC_TEST_PARAM_2 was passed correctly from the compose file
|
||||
if [[ "$log_output_3" == *"Test-param-2: CERC_TEST_PARAM_2_VALUE"* ]]; then
|
||||
echo "deployment compose config test: passed"
|
||||
else
|
||||
echo "deployment compose config test: FAILED"
|
||||
exit 1
|
||||
fi
|
||||
# Check the config variable CERC_TEST_PARAM_3 was passed correctly
|
||||
if [[ "$log_output_3" == *"Test-param-3: FAST"* ]]; then
|
||||
echo "deployment config test: passed"
|
||||
else
|
||||
echo "deployment config test: FAILED"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check that the ConfigMap is mounted and contains the expected content.
|
||||
log_output_4=$( $TEST_TARGET_SO deployment --dir $test_deployment_dir logs )
|
||||
if [[ "$log_output_4" == *"/config/test_config:"* ]] && [[ "$log_output_4" == *"dbfc7a4d-44a7-416d-b5f3-29842cc47650"* ]]; then
|
||||
echo "deployment ConfigMap test: passed"
|
||||
else
|
||||
echo "deployment ConfigMap test: FAILED"
|
||||
delete_cluster_exit
|
||||
fi
|
||||
|
||||
# Stop then start again and check the volume was preserved
|
||||
$TEST_TARGET_SO deployment --dir $test_deployment_dir stop
|
||||
# Sleep a bit just in case
|
||||
# sleep for longer to check if that's why the subsequent create cluster fails
|
||||
sleep 20
|
||||
$TEST_TARGET_SO deployment --dir $test_deployment_dir start
|
||||
log_output_5=$( $TEST_TARGET_SO deployment --dir $test_deployment_dir logs )
|
||||
if [[ "$log_output_5" == *"filesystem is old"* ]]; then
|
||||
echo "Retain volumes test: passed"
|
||||
else
|
||||
echo "Retain volumes test: FAILED"
|
||||
delete_cluster_exit
|
||||
fi
|
||||
|
||||
# Stop and clean up
|
||||
$TEST_TARGET_SO deployment --dir $test_deployment_dir stop --delete-volumes
|
||||
echo "Test passed"
|
||||
Reference in New Issue
Block a user