Skip to content

Commit c53b6e0

Browse files
authored
Interactive mode (CLI) + Prometheus (#1293)
Interactive mode + Prometheus
1 parent d198f2b commit c53b6e0

File tree

21 files changed

+346
-29
lines changed

21 files changed

+346
-29
lines changed

book/src/SUMMARY.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
- [Caching](framework/components/caching.md)
1818
- [Secrets]()
1919
- [Observability Stack](framework/observability/observability_stack.md)
20-
- [Metrics]()
20+
- [Metrics](framework/observability/metrics.md)
2121
- [Logs](framework/observability/logs.md)
2222
- [Profiling](framework/observability/profiling.md)
2323
- [Traces]()
@@ -36,6 +36,7 @@
3636
- [Chainlink]()
3737
- [RPC]()
3838
- [Loki]()
39+
- [Interactive](framework/interactive.md)
3940
- [Continuous Integration](ci/ci.md)
4041
- [Libraries](./libraries.md)
4142
- [Seth](./libs/seth.md)

book/src/framework/getting_started.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
# Getting started
22

3+
## Prerequisites
4+
- `Docker` ([OrbStack](https://orbstack.dev/) or [Docker Desktop](https://www.docker.com/products/docker-desktop/))
5+
- [Golang](https://go.dev/doc/install)
6+
37
## Test setup
48

59
To start writing tests create a directory for your project with `go.mod` and pull the framework
@@ -8,7 +12,6 @@ go get github.com/smartcontractkit/chainlink-testing-framework/framework
812
```
913

1014
Then download the CLI (runs from directory where you have `go.mod`)
11-
Make sure you have your GOPATH set: `export GOPATH=$HOME/go && export PATH=$PATH:$GOPATH/bin`
1215
```
1316
go get github.com/smartcontractkit/chainlink-testing-framework/framework/cmd && \
1417
go install github.com/smartcontractkit/chainlink-testing-framework/framework/cmd && \
54.5 KB
Loading

book/src/framework/interactive.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# Interactive
2+
3+
4+
For non-technical users or those building with Chainlink products outside of Golang, we offer an interactive method to deploy a NodeSet.
5+
6+
The only requirement is to have Docker running.
7+
8+
If you're on OS X, we recommend to use [OrbStack](https://orbstack.dev/).
9+
10+
For other platforms use [Docker Desktop](https://www.docker.com/products/docker-desktop/).
11+
12+
Download the latest CLI [here](https://github.com/smartcontractkit/chainlink-testing-framework/releases/tag/framework%2Fv0.1.6)
13+
14+
```
15+
./framework build node_set
16+
```
17+
Press `Ctrl+C` to remove the stack.
18+
19+
![img.png](images/interactive-node-set.png)
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# Metrics
2+
3+
We use Prometheus to collect metrics of Chainlink nodes and other services.
4+
5+
Check [Grafana](http://localhost:3000/explore?panes=%7B%22gGs%22:%7B%22datasource%22:%22PBFA97CFB590B2093%22,%22queries%22:%5B%7B%22refId%22:%22A%22,%22expr%22:%22%7Bjob%3D%5C%22ctf%5C%22%7D%22,%22range%22:true,%22instant%22:true,%22datasource%22:%7B%22type%22:%22prometheus%22,%22uid%22:%22PBFA97CFB590B2093%22%7D,%22editorMode%22:%22code%22,%22legendFormat%22:%22__auto%22%7D%5D,%22range%22:%7B%22from%22:%22now-5m%22,%22to%22:%22now%22%7D%7D%7D&schemaVersion=1&orgId=1) example query.
6+
7+
Queries:
8+
- All metrics of all containers
9+
```json
10+
{job="ctf"}
11+
```

book/src/overview.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ Its primary purpose is to help Chainlink developers create extensive integration
66

77
It can also be helpful to those who just want to use chainlink oracles in their projects to help test their contracts, or even for those that aren't using chainlink.
88

9-
This documentation is for:
9+
This documentation is primarily for:
1010
- Developers looking to write end-to-end tests
1111
- Quality Assurance Engineers aiming to test locally
1212

@@ -15,3 +15,5 @@ To get started with writing tests, refer to the [Framework](./framework/getting_
1515
[Repository](https://github.com/smartcontractkit/chainlink-testing-framework) contains two major pieces:
1616
- [Framework](framework/overview.md)
1717
- [Libraries](libraries.md)
18+
19+
If you're a non-technical user or want to build integration with Chainlink not in `Golang`, please refer to our [Interactive](framework/interactive.md) chapter.

framework/.changeset/v0.1.6.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
- Add Prometheus with docker metrics discovery
2+
- Add "interactive" mode for non-Golang developers or non-technical users

framework/cmd/interactive.go

Lines changed: 182 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,182 @@
1+
package main
2+
3+
import (
4+
"fmt"
5+
"github.com/charmbracelet/huh"
6+
"github.com/charmbracelet/huh/spinner"
7+
"github.com/smartcontractkit/chainlink-testing-framework/framework"
8+
"github.com/smartcontractkit/chainlink-testing-framework/framework/components/blockchain"
9+
"github.com/smartcontractkit/chainlink-testing-framework/framework/components/clnode"
10+
"github.com/smartcontractkit/chainlink-testing-framework/framework/components/postgres"
11+
"github.com/smartcontractkit/chainlink-testing-framework/framework/components/simple_node_set"
12+
"os"
13+
"os/signal"
14+
"sync"
15+
"syscall"
16+
)
17+
18+
type nodeSetForm struct {
19+
Network string
20+
CLVersion string
21+
Nodes int
22+
Observability bool
23+
Blockscout bool
24+
}
25+
26+
func createComponentsFromForm(form *nodeSetForm) error {
27+
var (
28+
bc *blockchain.Output
29+
_ *simple_node_set.Output
30+
err error
31+
)
32+
if err := framework.DefaultNetwork(&sync.Once{}); err != nil {
33+
return err
34+
}
35+
switch form.Network {
36+
case "anvil":
37+
f := func() {
38+
bc, err = blockchain.NewBlockchainNetwork(&blockchain.Input{
39+
Type: "anvil",
40+
Image: "f4hrenh9it/foundry",
41+
PullImage: true,
42+
Port: "8545",
43+
ChainID: "31337",
44+
})
45+
}
46+
err = spinner.New().
47+
Title("Creating anvil blockchain..").
48+
Action(f).
49+
Run()
50+
}
51+
switch form.Nodes {
52+
case 5:
53+
nspecs := make([]*clnode.Input, 0)
54+
for i := 0; i < form.Nodes; i++ {
55+
nspecs = append(nspecs, &clnode.Input{
56+
DbInput: &postgres.Input{
57+
Image: "postgres:15.6",
58+
PullImage: true,
59+
},
60+
Node: &clnode.NodeInput{
61+
Image: form.CLVersion,
62+
PullImage: true,
63+
},
64+
})
65+
}
66+
f := func() {
67+
_, err = simple_node_set.NewSharedDBNodeSet(&simple_node_set.Input{
68+
Nodes: 5,
69+
OverrideMode: "all",
70+
NodeSpecs: nspecs,
71+
}, bc, "")
72+
}
73+
err = spinner.New().
74+
Title("Creating node set..").
75+
Action(f).
76+
Run()
77+
}
78+
switch form.Observability {
79+
case true:
80+
if err = framework.NewPromtail(); err != nil {
81+
return err
82+
}
83+
if err := observabilityUp(); err != nil {
84+
return err
85+
}
86+
}
87+
switch form.Blockscout {
88+
case true:
89+
if err := blockscoutUp(); err != nil {
90+
return err
91+
}
92+
}
93+
return err
94+
}
95+
96+
func cleanup(form *nodeSetForm) error {
97+
var err error
98+
f := func() {
99+
err = cleanDockerResources()
100+
}
101+
err = spinner.New().
102+
Title("Removing docker resources..").
103+
Action(f).
104+
Run()
105+
switch form.Observability {
106+
case true:
107+
if err := observabilityDown(); err != nil {
108+
return err
109+
}
110+
}
111+
switch form.Blockscout {
112+
case true:
113+
if err := blockscoutDown(); err != nil {
114+
return err
115+
}
116+
}
117+
return err
118+
}
119+
120+
func runSetupForm() error {
121+
if !framework.IsDockerRunning() {
122+
return fmt.Errorf(`Docker daemon is not running!
123+
Please set up OrbStack (https://orbstack.dev/)
124+
or
125+
Docker Desktop (https://www.docker.com/products/docker-desktop/)
126+
`)
127+
}
128+
f := &nodeSetForm{}
129+
130+
form := huh.NewForm(
131+
huh.NewGroup(
132+
huh.NewSelect[string]().
133+
Title("Which network would you like to connect to?").
134+
Options(
135+
huh.NewOption("Anvil", "anvil"),
136+
).
137+
Value(&f.Network), // stores the selected network
138+
139+
huh.NewSelect[int]().
140+
Title("How many nodes do you need?").
141+
Options(
142+
huh.NewOption("5", 5),
143+
).
144+
Value(&f.Nodes), // stores the selected number of nodes
145+
146+
huh.NewSelect[string]().
147+
Title("Choose Chainlink node version").
148+
Options(
149+
huh.NewOption("public.ecr.aws/chainlink/chainlink:v2.17.0", "public.ecr.aws/chainlink/chainlink:v2.17.0")).
150+
Value(&f.CLVersion),
151+
huh.NewConfirm().
152+
Title("Do you need to spin up an observability stack?").
153+
Value(&f.Observability), // stores the observability option
154+
155+
huh.NewConfirm().
156+
Title("Do you need to spin up a Blockscout stack?").
157+
Value(&f.Blockscout), // stores the Blockscout option
158+
),
159+
)
160+
161+
err := form.Run()
162+
if err != nil {
163+
return fmt.Errorf("failed to run form: %w", err)
164+
}
165+
if err := createComponentsFromForm(f); err != nil {
166+
return err
167+
}
168+
169+
sigs := make(chan os.Signal, 1)
170+
signal.Notify(sigs, os.Interrupt, syscall.SIGTERM)
171+
go func() {
172+
<-sigs
173+
fmt.Println("\nReceived Ctrl+C, starting custom cleanup...")
174+
err := cleanup(f)
175+
if err != nil {
176+
panic(err)
177+
}
178+
os.Exit(0)
179+
}()
180+
framework.L.Info().Msg("Press Ctrl+C to remove the stack..")
181+
select {}
182+
}

framework/cmd/main.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,21 @@ func main() {
2727
Usage: "Chainlink Testing Framework CLI",
2828
UsageText: "'ctf' is a useful utility that can:\n- clean up test docker containers\n- modify test files\n- create a local observability stack with Grafana/Loki/Pyroscope",
2929
Commands: []*cli.Command{
30+
{
31+
Name: "build",
32+
Aliases: []string{"b"},
33+
Usage: "Build an environment interactively, suitable for non-technical users",
34+
Subcommands: []*cli.Command{
35+
{
36+
Name: "node_set",
37+
Aliases: []string{"ns"},
38+
Usage: "Builds a NodeSet and connect it to some networks",
39+
Action: func(c *cli.Context) error {
40+
return runSetupForm()
41+
},
42+
},
43+
},
44+
},
3045
{
3146
Name: "config",
3247
Aliases: []string{"c"},

framework/cmd/observability/compose/conf/prometheus.yml

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,9 @@ scrape_configs:
55
- job_name: 'ctf'
66
metrics_path: /metrics
77
docker_sd_configs:
8-
- host: "unix:///var/run/docker.sock" # Use the Docker socket to access container info
9-
refresh_interval: 10s # Refresh interval for discovering new containers
8+
- host: "unix:///var/run/docker.sock"
9+
refresh_interval: 20s
1010
relabel_configs:
11-
- source_labels: [ __meta_docker_container_label_com_docker_swarm_service_name ]
12-
regex: ".*"
13-
action: replace
14-
target_label: "service"
15-
16-
- source_labels: [ __meta_docker_container_port ]
17-
regex: '6688' # Only target containers exposing port 9090
11+
- source_labels: [ __meta_docker_port_private ]
12+
regex: '6688'
1813
action: keep

0 commit comments

Comments
 (0)