Skip to content

Commit 3060284

Browse files
committed
use chip ingress witout otel
1 parent 2c2fd91 commit 3060284

File tree

8 files changed

+263
-78
lines changed

8 files changed

+263
-78
lines changed

book/src/SUMMARY.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@
5454
- [NodeSet](framework/components/chainlink/nodeset.md)
5555
- [Storage](framework/components/storage.md)
5656
- [S3](framework/components/storage/s3.md)
57+
- [Chip Ingress Set](framework/components//chipingresset/chip_ingress.md)
5758
- [Clients]()
5859
- [Chainlink]()
5960
- [RPC]()
Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
# Chip Ingress Set
2+
3+
Chip Ingress Set is a composite component that collects Beholder events. It is a thin `testcontainers-go` wrapper over a Docker Compose file copied from the [Atlas](https://github.com/smartcontractkit/atlas/blob/master/chip-ingress/docker-compose.yml) repo.
4+
5+
It consists of 3 components:
6+
- Chip Ingress
7+
- Red Panda
8+
- Red Panda Console
9+
10+
## Configuration
11+
12+
To add it to your stack use following TOML:
13+
```toml
14+
[chip_ingress]
15+
compose_file='../../components/chip_ingress_set/docker-compose.yml'
16+
extra_docker_networks = ["my-existing-network"]
17+
```
18+
19+
Where compose file indicates the location of the `docker-compose.yml` file (remote URLs are supported) and `extra_docker_networks` an optional slice of existing Docker networks, to which whole stack should be connected to.
20+
21+
## Exposed ports
22+
23+
These 3 components expose a variety of ports, but the most important ones from the point of view of user interaction are:
24+
- schema registry port: `18081`
25+
- Kafka port: `19092`
26+
- Red Panda console port: `8080`
27+
28+
## Useful helper methods
29+
30+
Packge contains also a bunch of helper functions tha can:
31+
- create and delete Kafka topics
32+
- fetch `.proto` files from remote repositories and register them with Red Panda
33+
34+
35+
### Topic management
36+
```go
37+
import chipingressset "github.com/smartcontractkit/chainlink-testing-framework/framework/components/chip_ingress_set"
38+
39+
topicsErr := chipingressset.DeleteAllTopics(cmd.Context(), redPandaKafkaURLFlag)
40+
if topicsErr != nil {
41+
panic(topicsErr)
42+
}
43+
44+
createTopicsErr := chipingressset.CreateTopics(ctx, out.RedPanda.KafkaExternalURL, []string{"cre"})
45+
if createTopicsErr != nil {
46+
panic(createTopicsErr)
47+
}
48+
```
49+
50+
### Protobuf schema registration
51+
```go
52+
out, outErr := chipingressset.New(in.ChipIngress)
53+
if outErr != nil {
54+
panic(outErr)
55+
}
56+
57+
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute)
58+
defer cancel()
59+
60+
// we recommend to use GITHUB_TOKEN with read access to repositories with protos to avoid heavy rate limiting
61+
var client *github.Client
62+
if token := os.Getenv("GITHUB_TOKEN"); token != "" {
63+
ts := oauth2.StaticTokenSource(&oauth2.Token{AccessToken: token})
64+
tc := oauth2.NewClient(ctx, ts)
65+
client = github.NewClient(tc)
66+
} else {
67+
client = github.NewClient(nil)
68+
}
69+
70+
protoErr := chipingressset.DefaultRegisterAndFetchProtos(ctx, client, []chipingressset.RepoConfiguration{
71+
{
72+
Owner: "smartcontractkit",
73+
Repo: "chainlink-protos",
74+
Ref: "626c42d55bdcb36dffe0077fff58abba40acc3e5",
75+
Folders: []string{"workflows"},
76+
},
77+
}, out.RedPanda.SchemaRegistryExternalURL)
78+
if protoErr != nil {
79+
panic(protoErr)
80+
}
81+
```
82+
83+
Since `ProtoSchemaSet` has TOML tags you can also read it from a TOML file with this content:
84+
```toml
85+
[[proto_schema_set]]
86+
owner = 'smartcontractkit'
87+
repository = 'chainlink-protos'
88+
ref = '626c42d55bdcb36dffe0077fff58abba40acc3e5'
89+
folders = ['workflows']
90+
```
91+
92+
using this code:
93+
```go
94+
var protoSchemaSets []chipingressset.ProtoSchemaSet
95+
for _, schemaSet := range configFiles {
96+
file, fileErr := os.ReadFile(schemaSet)
97+
if fileErr != nil {
98+
return errors.Wrapf(fileErr, "failed to read proto schema set config file: %s", schemaSet)
99+
}
100+
101+
type protoSchemaSets struct {
102+
Sets []chipingressset.ProtoSchemaSet `toml:"proto_schema_set"`
103+
}
104+
105+
var sets protoSchemaSets
106+
if err := toml.Unmarshal(file, &sets); err != nil {
107+
return errors.Wrapf(err, "failed to unmarshal proto config file: %s", protoConfig)
108+
}
109+
110+
protoSchemaSets = append(reposConfigs, sets.Sets...)
111+
}
112+
```
113+
114+
Registration logic is very simple and should handle cases of protos that import other protos as long they are all available in the `ProtoSchemaSet`s provided to the registration function. That function uses an algorithm called "topological sorting by trail", which will try to register all protos in a loop until it cannot register any more protos or it has registered all of them. That allows us to skip dependency parsing completely.
115+
116+
Since Kafka doesn't have any automatic discoverability mechanism for subject - schema relationship (it has to be provided out-of-band) code currently only knows how to correctly register protos from [chainlink-protos](https://github.com/smartcontractkit/chainlink-protos) repository.

framework/components/chip_ingress_set/chip_ingress.go

Lines changed: 51 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -32,13 +32,14 @@ type RedPandaOutput struct {
3232
SchemaRegistryExternalURL string
3333
KafkaInternalURL string
3434
KafkaExternalURL string
35+
ConsoleExternalURL string
3536
}
3637

3738
type Input struct {
38-
ComposeFile string `toml:"compose_file"`
39-
Topics []string `toml:"topics"`
40-
Output *Output `toml:"output"`
41-
UseCache bool `toml:"use_cache"`
39+
ComposeFile string `toml:"compose_file"`
40+
ExtraDockerNetworks []string `toml:"extra_docker_networks"`
41+
Output *Output `toml:"output"`
42+
UseCache bool `toml:"use_cache"`
4243
}
4344

4445
func defaultChipIngress(in *Input) *Input {
@@ -49,12 +50,17 @@ func defaultChipIngress(in *Input) *Input {
4950
}
5051

5152
const (
53+
DEFAULT_STACK_NAME = "chip-ingress"
54+
5255
DEFAULT_CHIP_INGRESS_GRPC_PORT = "50051"
5356
DEFAULT_CHIP_INGRESS_SERVICE_NAME = "chip-ingress"
5457

5558
DEFAULT_RED_PANDA_SCHEMA_REGISTRY_PORT = "18081"
5659
DEFAULT_RED_PANDA_KAFKA_PORT = "19092"
5760
DEFAULT_RED_PANDA_SERVICE_NAME = "redpanda-0"
61+
62+
DEFAULT_RED_PANDA_CONSOLE_SERVICE_NAME = "redpanda-console"
63+
DEFAULT_RED_PANDA_CONSOLE_PORT = "8080"
5864
)
5965

6066
func New(in *Input) (*Output, error) {
@@ -69,7 +75,8 @@ func New(in *Input) (*Output, error) {
6975
}
7076

7177
in = defaultChipIngress(in)
72-
identifier := framework.DefaultTCName(DEFAULT_CHIP_INGRESS_SERVICE_NAME)
78+
identifier := framework.DefaultTCName(DEFAULT_STACK_NAME)
79+
framework.L.Debug().Str("Compose file", in.ComposeFile).Msgf("Starting Chip Ingress stack with identifier %s", framework.DefaultTCName(DEFAULT_STACK_NAME))
7380

7481
composeFilePath, fileErr := composeFilePath(in.ComposeFile)
7582
if fileErr != nil {
@@ -119,45 +126,50 @@ func New(in *Input) (*Output, error) {
119126
timeout := time.After(1 * time.Minute)
120127
tick := time.Tick(500 * time.Millisecond)
121128

122-
// so let's try to connect to the default network a couple of times, there must be a race condition in Docker
129+
// so let's try to connect to a Docker network a couple of times, there must be a race condition in Docker
123130
// and even when network sandbox has been created and container is running, this call can still fail
124131
// retrying is simpler than trying to figure out how to correctly wait for the network sandbox to be ready
125-
var connectDefaultNetwork = func() error {
132+
var connectNetwork = func(networkName string) error {
126133
for {
127134
select {
128135
case <-timeout:
129136
return fmt.Errorf("timeout while trying to connect chip-ingress to default network")
130137
case <-tick:
131138
if networkErr := cli.NetworkConnect(
132139
ctx,
133-
framework.DefaultNetworkName,
140+
networkName,
134141
chipIngressContainer.ID,
135142
&networkTypes.EndpointSettings{
136143
Aliases: []string{identifier},
137144
},
138145
); networkErr != nil && !strings.Contains(networkErr.Error(), "already exists in network") {
139-
fmt.Println("failed to connect to default network", networkErr)
146+
framework.L.Trace().Msgf("failed to connect to default network: %v", networkErr)
140147
continue
141148
}
142-
fmt.Println("connected to default network")
149+
framework.L.Trace().Msgf("connected to %s network", networkName)
143150
return nil
144151
}
145152
}
146153
}
147154

148-
if connectErr := connectDefaultNetwork(); connectErr != nil {
149-
return nil, errors.Wrap(connectErr, "failed to connect chip-ingress to default network")
150-
}
155+
networks := []string{framework.DefaultNetworkName}
156+
networks = append(networks, in.ExtraDockerNetworks...)
151157

152-
// verify that the container is connected to framework's network
153-
inspected, inspectErr := cli.ContainerInspect(ctx, chipIngressContainer.ID)
154-
if inspectErr != nil {
155-
return nil, errors.Wrapf(inspectErr, "failed to inspect container %s", chipIngressContainer.ID)
156-
}
158+
for _, networkName := range networks {
159+
framework.L.Debug().Msgf("Connecting chip-ingress to %s network", networkName)
160+
if connectErr := connectNetwork(networkName); connectErr != nil {
161+
return nil, errors.Wrapf(connectErr, "failed to connect chip-ingress to %s network", networkName)
162+
}
163+
// verify that the container is connected to framework's network
164+
inspected, inspectErr := cli.ContainerInspect(ctx, chipIngressContainer.ID)
165+
if inspectErr != nil {
166+
return nil, errors.Wrapf(inspectErr, "failed to inspect container %s", chipIngressContainer.ID)
167+
}
157168

158-
_, ok := inspected.NetworkSettings.Networks[framework.DefaultNetworkName]
159-
if !ok {
160-
return nil, fmt.Errorf("container %s is NOT on network %s", chipIngressContainer.ID, framework.DefaultNetworkName)
169+
_, ok := inspected.NetworkSettings.Networks[networkName]
170+
if !ok {
171+
return nil, fmt.Errorf("container %s is NOT on network %s", chipIngressContainer.ID, networkName)
172+
}
161173
}
162174

163175
// get hosts and ports for chip-ingress and redpanda
@@ -188,6 +200,20 @@ func New(in *Input) (*Output, error) {
188200
return nil, errors.Wrap(redpandaExternalSchemaRegistryPortErr, "failed to get mapped port for Red Panda")
189201
}
190202

203+
redpandaConsoleContainer, redpandaConsoleErr := stack.ServiceContainer(ctx, DEFAULT_RED_PANDA_CONSOLE_SERVICE_NAME)
204+
if redpandaConsoleErr != nil {
205+
return nil, errors.Wrap(redpandaConsoleErr, "failed to get redpanda-console container")
206+
}
207+
208+
redpandaExternalConsoleHost, redpandaExternalConsoleHostErr := redpandaConsoleContainer.Host(ctx)
209+
if redpandaExternalConsoleHostErr != nil {
210+
return nil, errors.Wrap(redpandaExternalConsoleHostErr, "failed to get host for Red Panda Console")
211+
}
212+
redpandaExternalConsolePort, redpandaExternalConsolePortErr := redpandaConsoleContainer.MappedPort(ctx, DEFAULT_RED_PANDA_CONSOLE_PORT)
213+
if redpandaExternalConsolePortErr != nil {
214+
return nil, errors.Wrap(redpandaExternalConsolePortErr, "failed to get mapped port for Red Panda Console")
215+
}
216+
191217
output := &Output{
192218
ChipIngress: &ChipIngressOutput{
193219
GRPCInternalURL: fmt.Sprintf("http://%s:%s", DEFAULT_CHIP_INGRESS_SERVICE_NAME, DEFAULT_CHIP_INGRESS_GRPC_PORT),
@@ -198,9 +224,12 @@ func New(in *Input) (*Output, error) {
198224
SchemaRegistryExternalURL: fmt.Sprintf("http://%s:%s", redpandaExternalHost, redpandaExternalSchemaRegistryPort.Port()),
199225
KafkaInternalURL: fmt.Sprintf("%s:%s", DEFAULT_RED_PANDA_SERVICE_NAME, DEFAULT_RED_PANDA_KAFKA_PORT),
200226
KafkaExternalURL: fmt.Sprintf("%s:%s", redpandaExternalHost, redpandaExternalKafkaPort.Port()),
227+
ConsoleExternalURL: fmt.Sprintf("http://%s:%s", redpandaExternalConsoleHost, redpandaExternalConsolePort.Port()),
201228
},
202229
}
203230

231+
framework.L.Info().Msg("Chip Ingress stack start")
232+
204233
return output, nil
205234
}
206235

@@ -216,7 +245,7 @@ func composeFilePath(rawFilePath string) (string, error) {
216245
}
217246
defer resp.Body.Close()
218247

219-
tempFile, tempErr := os.CreateTemp(".", "chip-ingress-docker-compose.yml")
248+
tempFile, tempErr := os.CreateTemp("", "chip-ingress-docker-compose-*.yml")
220249
if tempErr != nil {
221250
return "", errors.Wrap(tempErr, "failed to create temp file")
222251
}

framework/components/chip_ingress_set/docker-compose.yml

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
1+
# copied from https://github.com/smartcontractkit/atlas/blob/master/chip-ingress/docker-compose.yml
12
services:
23

34
chip-ingress:
4-
image: chip-ingress:latest
5+
image: ${CHIP_INGRESS_IMAGE:-chip-ingress:latest}
56
container_name: chip-ingress
67
depends_on:
78
- redpanda-0
8-
- otel-lgtm
99
restart: on-failure
1010
tty: true
1111
command: ["write-service"]
@@ -15,7 +15,9 @@ services:
1515
SERVER_METRICS_PORT: "9090"
1616
SERVER_HEALTHCHECKS_PORT: "9091"
1717
SERVER_METRICS_IMPLEMENTATION: "otel"
18-
SERVER_METRICS_OTEL_EXPORTER_GRPC_ENDPOINT: ${SERVER_METRICS_OTEL_EXPORTER_GRPC_ENDPOINT:-otel-lgtm:4317}
18+
# this has been modified from the original docker-compose.yml to use localhost:4317 as we don't have otel-lgtm service in this stack
19+
# but we have our own observability stack, which is accessible via localhost (after starting it with ctf obs u)
20+
SERVER_METRICS_OTEL_EXPORTER_GRPC_ENDPOINT: ${SERVER_METRICS_OTEL_EXPORTER_GRPC_ENDPOINT:-localhost:4317}
1921
KAFKA_BROKERS: "redpanda-0:9092"
2022
SCHEMA_REGISTRY_URL: "http://redpanda-0:8081"
2123
# this has been modified and default values were removed, somehow we cannot override them in testcontainers-go
@@ -33,8 +35,8 @@ services:
3335
- "9090:9090"
3436
- "9092:9091"
3537
healthcheck:
38+
# this has been modified from the original docker-compose.yml to use grpc_health_probe
3639
test: [ "CMD", "grpc_health_probe", "-addr=localhost:50051" ]
37-
# test: [ "CMD-SHELL", "sleep 1"]
3840
interval: 200ms
3941
timeout: 10s
4042
retries: 10
@@ -96,11 +98,5 @@ services:
9698
depends_on:
9799
- redpanda-0
98100

99-
otel-lgtm:
100-
image: grafana/otel-lgtm
101-
ports:
102-
- "3000:3000"
103-
- "4317:4317"
104-
- "4318:4318"
105-
- "3100:3100"
106-
101+
# removed otel-lgtm service as it's not needed for the stack to work
102+
# and we have our own observability stack

0 commit comments

Comments
 (0)