Commit ad02c43c authored by Carlos Bermudez Porto's avatar Carlos Bermudez Porto Committed by GitHub

feat: add inputs for additional grafana dashboards (#279)

Co-authored-by: default avatarGyanendra Mishra <anomaly.the@gmail.com>
parent d0eff2e9
# Ethereum Package # Ethereum Package
![Run of the Ethereum Network Package](run.gif) ![Run of the Ethereum Network Package](run.gif)
This is a [Kurtosis][kurtosis-repo] package that will spin up a private Ethereum testnet over Docker or Kubernetes with multi-client support, Flashbot's `mev-boost` infrastructure for PBS-related testing/validation, and other useful network tools (transaction spammer, monitoring tools, etc). Kurtosis packages are entirely reproducible and composable, so this will work the same way over Docker or Kubernetes, in the cloud or locally on your machine. This is a [Kurtosis][kurtosis-repo] package that will spin up a private Ethereum testnet over Docker or Kubernetes with multi-client support, Flashbot's `mev-boost` infrastructure for PBS-related testing/validation, and other useful network tools (transaction spammer, monitoring tools, etc). Kurtosis packages are entirely reproducible and composable, so this will work the same way over Docker or Kubernetes, in the cloud or locally on your machine.
Specifically, this [package][package-reference] will: Specifically, this [package][package-reference] will:
1. Generate Execution Layer (EL) & Consensus Layer (CL) genesis information using [the Ethereum genesis generator](https://github.com/ethpandaops/ethereum-genesis-generator). 1. Generate Execution Layer (EL) & Consensus Layer (CL) genesis information using [the Ethereum genesis generator](https://github.com/ethpandaops/ethereum-genesis-generator).
2. Configure & bootstrap a network of Ethereum nodes of *n* size using the genesis data generated above 2. Configure & bootstrap a network of Ethereum nodes of *n* size using the genesis data generated above
3. Spin up a [transaction spammer](https://github.com/MariusVanDerWijden/tx-fuzz) to send fake transactions to the network 3. Spin up a [transaction spammer](https://github.com/MariusVanDerWijden/tx-fuzz) to send fake transactions to the network
...@@ -11,6 +13,7 @@ Specifically, this [package][package-reference] will: ...@@ -11,6 +13,7 @@ Specifically, this [package][package-reference] will:
5. Spin up a Grafana and Prometheus instance to observe the network 5. Spin up a Grafana and Prometheus instance to observe the network
Optional features (enabled via flags or parameter files at runtime): Optional features (enabled via flags or parameter files at runtime):
* Block until the Beacon nodes finalize an epoch (i.e. finalized_epoch > 0) * Block until the Beacon nodes finalize an epoch (i.e. finalized_epoch > 0)
* Spin up & configure parameters for the infrastructure behind Flashbot's implementation of PBS using `mev-boost`, in either `full` or `mock` mode. More details [here](./README.md#proposer-builder-separation-pbs-implementation-via-flashbots-mev-boost-protocol). * Spin up & configure parameters for the infrastructure behind Flashbot's implementation of PBS using `mev-boost`, in either `full` or `mock` mode. More details [here](./README.md#proposer-builder-separation-pbs-implementation-via-flashbots-mev-boost-protocol).
* Spin up & connect the network to a [beacon metrics gazer service](https://github.com/dapplion/beacon-metrics-gazer) to collect network-wide participation metrics. * Spin up & connect the network to a [beacon metrics gazer service](https://github.com/dapplion/beacon-metrics-gazer) to collect network-wide participation metrics.
...@@ -20,15 +23,19 @@ Optional features (enabled via flags or parameter files at runtime): ...@@ -20,15 +23,19 @@ Optional features (enabled via flags or parameter files at runtime):
* Generate keystores for each node in parallel * Generate keystores for each node in parallel
## Quickstart ## Quickstart
1. [Install Docker & start the Docker Daemon if you haven't done so already][docker-installation] 1. [Install Docker & start the Docker Daemon if you haven't done so already][docker-installation]
2. [Install the Kurtosis CLI, or upgrade it to the latest version if it's already installed][kurtosis-cli-installation] 2. [Install the Kurtosis CLI, or upgrade it to the latest version if it's already installed][kurtosis-cli-installation]
3. Run the package with default configurations from the command line: 3. Run the package with default configurations from the command line:
```bash ```bash
kurtosis run --enclave my-testnet github.com/kurtosis-tech/ethereum-package kurtosis run --enclave my-testnet github.com/kurtosis-tech/ethereum-package
``` ```
#### Run with your own configuration #### Run with your own configuration
Kurtosis packages are parameterizable, meaning you can customize your network and its behavior to suit your needs by storing parameters in a file that you can pass in at runtime like so: Kurtosis packages are parameterizable, meaning you can customize your network and its behavior to suit your needs by storing parameters in a file that you can pass in at runtime like so:
```bash ```bash
kurtosis run --enclave my-testnet github.com/kurtosis-tech/ethereum-package "$(cat ~/network_params.json)" kurtosis run --enclave my-testnet github.com/kurtosis-tech/ethereum-package "$(cat ~/network_params.json)"
``` ```
...@@ -36,40 +43,51 @@ kurtosis run --enclave my-testnet github.com/kurtosis-tech/ethereum-package "$(c ...@@ -36,40 +43,51 @@ kurtosis run --enclave my-testnet github.com/kurtosis-tech/ethereum-package "$(c
Where `network_params.json` contains the parameters for your network in your home directory. Where `network_params.json` contains the parameters for your network in your home directory.
#### Run on Kubernetes #### Run on Kubernetes
Kurtosis packages work the same way over Docker or on Kubernetes. Please visit our [Kubernetes docs](https://docs.kurtosis.com/k8s) to learn how to spin up a private testnet on a Kubernetes cluster. Kurtosis packages work the same way over Docker or on Kubernetes. Please visit our [Kubernetes docs](https://docs.kurtosis.com/k8s) to learn how to spin up a private testnet on a Kubernetes cluster.
#### Tear down #### Tear down
The testnet will reside in an [enclave][enclave] - an isolated, ephemeral environment. The enclave and its contents (e.g. running containers, files artifacts, etc) will persist until torn down. You can remove an enclave and its contents with: The testnet will reside in an [enclave][enclave] - an isolated, ephemeral environment. The enclave and its contents (e.g. running containers, files artifacts, etc) will persist until torn down. You can remove an enclave and its contents with:
```
```bash
kurtosis enclave rm -f my-testnet kurtosis enclave rm -f my-testnet
``` ```
## Management ## Management
The [Kurtosis CLI](https://docs.kurtosis.com/cli) can be used to inspect and interact with the network. The [Kurtosis CLI](https://docs.kurtosis.com/cli) can be used to inspect and interact with the network.
For example, if you need shell access, simply run: For example, if you need shell access, simply run:
```
```bash
kurtosis service shell my-testnet $SERVICE_NAME kurtosis service shell my-testnet $SERVICE_NAME
``` ```
And if you need the logs for a service, simply run: And if you need the logs for a service, simply run:
```
```bash
kurtosis service logs my-testnet $SERVICE_NAME kurtosis service logs my-testnet $SERVICE_NAME
``` ```
Check out the full list of CLI commands [here](https://docs.kurtosis.com/cli) Check out the full list of CLI commands [here](https://docs.kurtosis.com/cli)
## Debugging ## Debugging
To grab the genesis files for the network, simply run: To grab the genesis files for the network, simply run:
```
```bash
kurtosis files download my-testnet $FILE_NAME $OUTPUT_DIRECTORY kurtosis files download my-testnet $FILE_NAME $OUTPUT_DIRECTORY
``` ```
For example, to retrieve the Execution Layer (EL) genesis data, run: For example, to retrieve the Execution Layer (EL) genesis data, run:
```
```bash
kurtosis files download my-testnet el-genesis-data ~/Downloads kurtosis files download my-testnet el-genesis-data ~/Downloads
``` ```
## Configuration ## Configuration
To configure the package behaviour, you can modify your `network_params.json` file. The full JSON schema that can be passed in is as follows with the defaults provided: To configure the package behaviour, you can modify your `network_params.json` file. The full JSON schema that can be passed in is as follows with the defaults provided:
<details> <details>
...@@ -230,7 +248,7 @@ To configure the package behaviour, you can modify your `network_params.json` fi ...@@ -230,7 +248,7 @@ To configure the package behaviour, you can modify your `network_params.json` fi
// - A light beacon chain explorer will be launched // - A light beacon chain explorer will be launched
// - Default: ["tx_spammer", "blob_spammer", "cl_fork_mon", "el_forkmon", "beacon_metrics_gazer", "dora"," "prometheus_grafana"] // - Default: ["tx_spammer", "blob_spammer", "cl_fork_mon", "el_forkmon", "beacon_metrics_gazer", "dora"," "prometheus_grafana"]
"additional_services": [ "additional_services": [
"tx_spammer", "tx_spammer",
"blob_spammer", "blob_spammer",
"goomy_blob" "goomy_blob"
"cl_forkmon", "cl_forkmon",
...@@ -296,9 +314,12 @@ To configure the package behaviour, you can modify your `network_params.json` fi ...@@ -296,9 +314,12 @@ To configure the package behaviour, you can modify your `network_params.json` fi
// A custom flood script that increases the balance of the coinbase addresss leading to more reliable // A custom flood script that increases the balance of the coinbase addresss leading to more reliable
// payload delivery // payload delivery
"launch_custom_flood": false "launch_custom_flood": false
} },
// A list of locators for grafana dashboards to be loaded be the grafana service
"grafana_additional_dashboards": []
} }
``` ```
</details> </details>
#### Example configurations #### Example configurations
...@@ -341,6 +362,7 @@ To configure the package behaviour, you can modify your `network_params.json` fi ...@@ -341,6 +362,7 @@ To configure the package behaviour, you can modify your `network_params.json` fi
"global_client_log_level": "info" "global_client_log_level": "info"
} }
``` ```
</details> </details>
<details> <details>
...@@ -376,6 +398,7 @@ To configure the package behaviour, you can modify your `network_params.json` fi ...@@ -376,6 +398,7 @@ To configure the package behaviour, you can modify your `network_params.json` fi
"launch_additional_services": false "launch_additional_services": false
} }
``` ```
</details> </details>
<details> <details>
...@@ -413,6 +436,7 @@ To configure the package behaviour, you can modify your `network_params.json` fi ...@@ -413,6 +436,7 @@ To configure the package behaviour, you can modify your `network_params.json` fi
"launch_additional_services": false "launch_additional_services": false
} }
``` ```
</details> </details>
<details> <details>
...@@ -433,15 +457,19 @@ To configure the package behaviour, you can modify your `network_params.json` fi ...@@ -433,15 +457,19 @@ To configure the package behaviour, you can modify your `network_params.json` fi
"snooper_enabled": true "snooper_enabled": true
} }
``` ```
</details> </details>
## Proposer Builder Separation (PBS) emulation ## Proposer Builder Separation (PBS) emulation
To spin up the network of Ethereum nodes with an external block building network (using Flashbot's `mev-boost` protocol), simply use: To spin up the network of Ethereum nodes with an external block building network (using Flashbot's `mev-boost` protocol), simply use:
``` ```
kurtosis run github.com/kurtosis-tech/ethereum-package '{"mev_type": "full"}' kurtosis run github.com/kurtosis-tech/ethereum-package '{"mev_type": "full"}'
``` ```
Starting your network up with `"mev_type": "full"` will instantiate and connect the following infrastructure to your network: Starting your network up with `"mev_type": "full"` will instantiate and connect the following infrastructure to your network:
1. `Flashbot's block builder & CL validator + beacon` - A modified Geth client that builds blocks. The CL validator and beacon clients are lighthouse clients configured to receive payloads from the relay. 1. `Flashbot's block builder & CL validator + beacon` - A modified Geth client that builds blocks. The CL validator and beacon clients are lighthouse clients configured to receive payloads from the relay.
2. `mev-relay-api` - Services that provide APIs for (a) proposers, (b) block builders, (c) data 2. `mev-relay-api` - Services that provide APIs for (a) proposers, (b) block builders, (c) data
3. `mev-relay-website` - A website to monitor payloads that have been delivered 3. `mev-relay-website` - A website to monitor payloads that have been delivered
...@@ -460,7 +488,6 @@ It is recommended to use non zero value for `capella_fork_epoch` by setting `net ...@@ -460,7 +488,6 @@ It is recommended to use non zero value for `capella_fork_epoch` by setting `net
in the arguments passed with `mev_type` set to `full`. in the arguments passed with `mev_type` set to `full`.
</details> </details>
This package also supports a `"mev_type": "mock"` mode that will only bring up: This package also supports a `"mev_type": "mock"` mode that will only bring up:
1. `mock-builder` - a server that listens for builder API directives and responds with payloads built using an execution client 1. `mock-builder` - a server that listens for builder API directives and responds with payloads built using an execution client
...@@ -504,9 +531,11 @@ Then, run the dev loop: ...@@ -504,9 +531,11 @@ Then, run the dev loop:
1. Make your code changes 1. Make your code changes
1. Rebuild and re-run the package by running the following from the root of the repo: 1. Rebuild and re-run the package by running the following from the root of the repo:
```bash ```bash
kurtosis run . "{}" kurtosis run . "{}"
``` ```
NOTE 1: You can change the value of the second positional argument flag to pass in extra configuration to the package per the "Configuration" section above! NOTE 1: You can change the value of the second positional argument flag to pass in extra configuration to the package per the "Configuration" section above!
NOTE 2: The second positional argument accepts JSON. NOTE 2: The second positional argument accepts JSON.
...@@ -528,7 +557,5 @@ When you're happy with your changes: ...@@ -528,7 +557,5 @@ When you're happy with your changes:
[docker-installation]: https://docs.docker.com/get-docker/ [docker-installation]: https://docs.docker.com/get-docker/
[kurtosis-cli-installation]: https://docs.kurtosis.com/install [kurtosis-cli-installation]: https://docs.kurtosis.com/install
[kurtosis-repo]: https://github.com/kurtosis-tech/kurtosis [kurtosis-repo]: https://github.com/kurtosis-tech/kurtosis
[using-the-cli]: https://docs.kurtosis.com/cli
[enclave]: https://docs.kurtosis.com/concepts-reference/enclaves/ [enclave]: https://docs.kurtosis.com/concepts-reference/enclaves/
[package-reference]: https://docs.kurtosis.com/concepts-reference/packages [package-reference]: https://docs.kurtosis.com/concepts-reference/packages
...@@ -336,6 +336,7 @@ def run(plan, args={}): ...@@ -336,6 +336,7 @@ def run(plan, args={}):
grafana_datasource_config_template, grafana_datasource_config_template,
grafana_dashboards_config_template, grafana_dashboards_config_template,
prometheus_private_url, prometheus_private_url,
additional_dashboards=args_with_right_defaults.grafana_additional_dashboards,
) )
plan.print("Succesfully launched grafana") plan.print("Succesfully launched grafana")
......
...@@ -51,5 +51,6 @@ ...@@ -51,5 +51,6 @@
"mev_flood_extra_args": [], "mev_flood_extra_args": [],
"mev_flood_seconds_per_bundle": 15, "mev_flood_seconds_per_bundle": 15,
"launch_custom_flood": false "launch_custom_flood": false
} },
"grafana_additional_dashboards": []
} }
...@@ -3,7 +3,7 @@ static_files = import_module("../static_files/static_files.star") ...@@ -3,7 +3,7 @@ static_files = import_module("../static_files/static_files.star")
SERVICE_NAME = "grafana" SERVICE_NAME = "grafana"
IMAGE_NAME = "grafana/grafana-enterprise:9.2.3" IMAGE_NAME = "grafana/grafana-enterprise:9.5.12"
HTTP_PORT_ID = "http" HTTP_PORT_ID = "http"
HTTP_PORT_NUMBER_UINT16 = 3000 HTTP_PORT_NUMBER_UINT16 = 3000
...@@ -19,6 +19,16 @@ GRAFANA_CONFIG_DIRPATH_ON_SERVICE = "/config" ...@@ -19,6 +19,16 @@ GRAFANA_CONFIG_DIRPATH_ON_SERVICE = "/config"
GRAFANA_DASHBOARDS_DIRPATH_ON_SERVICE = "/dashboards" GRAFANA_DASHBOARDS_DIRPATH_ON_SERVICE = "/dashboards"
GRAFANA_DASHBOARDS_FILEPATH_ON_SERVICE = GRAFANA_DASHBOARDS_DIRPATH_ON_SERVICE GRAFANA_DASHBOARDS_FILEPATH_ON_SERVICE = GRAFANA_DASHBOARDS_DIRPATH_ON_SERVICE
GRAFANA_ADDITIONAL_DASHBOARDS_FOLDER_NAME = "grafana-additional-dashboards-{0}"
GRAFANA_ADDITIONAL_DASHBOARDS_MERGED_STORED_PATH_FORMAT = (
GRAFANA_DASHBOARDS_DIRPATH_ON_SERVICE + "/*"
)
GRAFANA_ADDITIONAL_DASHBOARDS_FILEPATH_ON_SERVICE = "/additional-dashobards"
GRAFANA_ADDITIONAL_DASHBOARDS_FILEPATH_ON_SERVICE_FORMAT = (
GRAFANA_ADDITIONAL_DASHBOARDS_FILEPATH_ON_SERVICE + "/{0}"
)
GRAFANA_ADDITIONAL_DASHBOARDS_SERVICE_PATH_KEY = "ServicePath"
GRANAFA_ADDITIONAL_DASHBOARDS_ARTIFACT_NAME_KEY = "ArtifactName"
USED_PORTS = { USED_PORTS = {
HTTP_PORT_ID: shared_utils.new_port_spec( HTTP_PORT_ID: shared_utils.new_port_spec(
...@@ -34,19 +44,29 @@ def launch_grafana( ...@@ -34,19 +44,29 @@ def launch_grafana(
datasource_config_template, datasource_config_template,
dashboard_providers_config_template, dashboard_providers_config_template,
prometheus_private_url, prometheus_private_url,
additional_dashboards=[],
): ):
( (
grafana_config_artifacts_uuid, grafana_config_artifacts_uuid,
grafana_dashboards_artifacts_uuid, grafana_dashboards_artifacts_uuid,
grafana_additional_dashboards_data,
) = get_grafana_config_dir_artifact_uuid( ) = get_grafana_config_dir_artifact_uuid(
plan, plan,
datasource_config_template, datasource_config_template,
dashboard_providers_config_template, dashboard_providers_config_template,
prometheus_private_url, prometheus_private_url,
additional_dashboards=additional_dashboards,
)
merged_dashboards_artifact_name = merge_dashboards_artifacts(
plan,
grafana_dashboards_artifacts_uuid,
grafana_additional_dashboards_data,
) )
config = get_config( config = get_config(
grafana_config_artifacts_uuid, grafana_dashboards_artifacts_uuid grafana_config_artifacts_uuid,
merged_dashboards_artifact_name,
) )
plan.add_service(SERVICE_NAME, config) plan.add_service(SERVICE_NAME, config)
...@@ -57,6 +77,7 @@ def get_grafana_config_dir_artifact_uuid( ...@@ -57,6 +77,7 @@ def get_grafana_config_dir_artifact_uuid(
datasource_config_template, datasource_config_template,
dashboard_providers_config_template, dashboard_providers_config_template,
prometheus_private_url, prometheus_private_url,
additional_dashboards=[],
): ):
datasource_data = new_datasource_config_template_data(prometheus_private_url) datasource_data = new_datasource_config_template_data(prometheus_private_url)
datasource_template_and_data = shared_utils.new_template_and_data( datasource_template_and_data = shared_utils.new_template_and_data(
...@@ -86,10 +107,21 @@ def get_grafana_config_dir_artifact_uuid( ...@@ -86,10 +107,21 @@ def get_grafana_config_dir_artifact_uuid(
static_files.GRAFANA_DASHBOARDS_CONFIG_DIRPATH, name="grafana-dashboards" static_files.GRAFANA_DASHBOARDS_CONFIG_DIRPATH, name="grafana-dashboards"
) )
return grafana_config_artifacts_name, grafana_dashboards_artifacts_name grafana_additional_dashboards_data = upload_additional_dashboards(
plan, additional_dashboards
)
return (
grafana_config_artifacts_name,
grafana_dashboards_artifacts_name,
grafana_additional_dashboards_data,
)
def get_config(grafana_config_artifacts_name, grafana_dashboards_artifacts_name): def get_config(
grafana_config_artifacts_name,
grafana_dashboards_artifacts_name,
):
return ServiceConfig( return ServiceConfig(
image=IMAGE_NAME, image=IMAGE_NAME,
ports=USED_PORTS, ports=USED_PORTS,
...@@ -113,3 +145,58 @@ def new_datasource_config_template_data(prometheus_url): ...@@ -113,3 +145,58 @@ def new_datasource_config_template_data(prometheus_url):
def new_dashboard_providers_config_template_data(dashboards_dirpath): def new_dashboard_providers_config_template_data(dashboards_dirpath):
return {"DashboardsDirpath": dashboards_dirpath} return {"DashboardsDirpath": dashboards_dirpath}
def upload_additional_dashboards(plan, additional_dashboards):
data = []
for index, dashboard_src in enumerate(additional_dashboards):
additional_dashboard_folder_name = (
GRAFANA_ADDITIONAL_DASHBOARDS_FOLDER_NAME.format(index)
)
additional_dashboard_service_path = (
GRAFANA_ADDITIONAL_DASHBOARDS_FILEPATH_ON_SERVICE_FORMAT.format(
additional_dashboard_folder_name,
)
)
additional_dashboard_artifact_name = plan.upload_files(
dashboard_src,
)
data.append(
{
GRAFANA_ADDITIONAL_DASHBOARDS_SERVICE_PATH_KEY: additional_dashboard_service_path,
GRANAFA_ADDITIONAL_DASHBOARDS_ARTIFACT_NAME_KEY: additional_dashboard_artifact_name,
}
)
return data
def merge_dashboards_artifacts(
plan,
grafana_dashboards_artifacts_name,
grafana_additional_dashboards_data=[],
):
if len(grafana_additional_dashboards_data) == 0:
return grafana_dashboards_artifacts_name
files = {
GRAFANA_DASHBOARDS_DIRPATH_ON_SERVICE: grafana_dashboards_artifacts_name,
}
for additional_dashboard_data in grafana_additional_dashboards_data:
files[
additional_dashboard_data[GRAFANA_ADDITIONAL_DASHBOARDS_SERVICE_PATH_KEY]
] = additional_dashboard_data[GRANAFA_ADDITIONAL_DASHBOARDS_ARTIFACT_NAME_KEY]
result = plan.run_sh(
run="find "
+ GRAFANA_ADDITIONAL_DASHBOARDS_FILEPATH_ON_SERVICE
+ " -type f -exec cp {} "
+ GRAFANA_DASHBOARDS_DIRPATH_ON_SERVICE
+ " \\;",
files=files,
store=[
GRAFANA_ADDITIONAL_DASHBOARDS_MERGED_STORED_PATH_FORMAT,
],
)
return result.files_artifacts[0]
...@@ -61,6 +61,7 @@ def parse_input(plan, input_args): ...@@ -61,6 +61,7 @@ def parse_input(plan, input_args):
result["mev_params"] = get_default_mev_params() result["mev_params"] = get_default_mev_params()
result["launch_additional_services"] = True result["launch_additional_services"] = True
result["additional_services"] = DEFAULT_ADDITIONAL_SERVICES result["additional_services"] = DEFAULT_ADDITIONAL_SERVICES
result["grafana_additional_dashboards"] = []
for attr in input_args: for attr in input_args:
value = input_args[attr] value = input_args[attr]
...@@ -177,6 +178,7 @@ def parse_input(plan, input_args): ...@@ -177,6 +178,7 @@ def parse_input(plan, input_args):
mev_type=result["mev_type"], mev_type=result["mev_type"],
snooper_enabled=result["snooper_enabled"], snooper_enabled=result["snooper_enabled"],
parallel_keystore_generation=result["parallel_keystore_generation"], parallel_keystore_generation=result["parallel_keystore_generation"],
grafana_additional_dashboards=result["grafana_additional_dashboards"],
) )
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment