Skip to content

Commit 1886317

Browse files
authored
feat(resource): Config V2 (#152)
* Generate component ID * test id change * lint: package comment * feat(resource): Connectors for configuration v2 (#141) * add connectors * support delete * move readRolloutOptions() * WIP: We need component ID to be generated before apply * generate connector id * Remove test file * feat: Configuration V2 with routing (#143) * support delete * WIP: We need component ID to be generated before apply * Remove test file * rough working concept * test some advanced routing * remove route id, bindplane can generate it * input validation * resolve validation func * linter * fix issue with telemetry type and route id not persisting * feat: Configuration V2 Processors (#144) * support delete * WIP: We need component ID to be generated before apply * test some advanced routing * remove route id, bindplane can generate it * input validation * resolve validation func * fix issue with telemetry type and route id not persisting * WIP: We need component ID to be generated before apply * implement create * implement read * sync tests * chore: Test against v1.74.0 - current (#145) * lets see which versions work :) * tighten up versions * add version notice * doc processor groups on config v2 (#146) * feat: Config v2 connectors (#147) * add connector to config v2 schema * fix tests from bad rebase upstream * support connectors in the configuration * chore: Config v2 route handling refactor (#148) * refactor route parsing * Ensure routes returned are not nil * refactor config v2 read routes * typo * fix: Config v2 routes should use TypeSet to avoid ordering requirements (#149) * Fix an issue where the config v2 read func was not comparing route_id correctly * refactor RoutesToState further * use TypeSet for routes in order to avoid ordering constraint * ci * Route (#150) * unify route schema * implement route_id and enable connector support * add license * linter fixes * doc * fix bad rebase
1 parent 2b770fe commit 1886317

File tree

19 files changed

+3234
-51
lines changed

19 files changed

+3234
-51
lines changed

.github/workflows/ci.yml

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -193,15 +193,19 @@ jobs:
193193
bindplane_version:
194194
- "latest"
195195
- "module" # Use the current Go module version
196+
- "v1.86.0"
196197
- "v1.85.0" # v2 config released as beta
197198
- "v1.84.0"
199+
- "v1.83.0"
200+
- "v1.82.0"
201+
- "v1.81.0"
198202
- "v1.80.0"
199-
- "v1.73.0"
200-
- "v1.71.0"
201-
- "v1.70.0" # Routes introduced. Older clients work against 1.70, but 1.70 client will not work against older bindplane
202-
- "v1.66.0"
203-
- "v1.50.0"
204-
- "v1.44.0"
203+
- "v1.79.0" # v1.77.0 and v1.78.0 were never released
204+
205+
# v1.70.0 introduced v2 config and routes behind a feature flag
206+
# There were some growing pains and bugs. v1.76.0 is consider the
207+
# minimum supported server version for the provider.
208+
- "v1.76.0"
205209
steps:
206210
- name: Check out source code
207211
uses: actions/checkout@v4

client/client.go

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,38 @@ func (i *BindPlane) Rollout(name string) error {
9898
return err
9999
}
100100

101+
// Connector takes a name and returns the matching connector
102+
func (i *BindPlane) Connector(name string) (*model.Connector, error) {
103+
r, err := i.Client.Resource(context.Background(), model.KindConnector, name)
104+
if err != nil {
105+
// Do not return an error if the resource is not found. Terraform
106+
// will understand that the resource does not exist when it receives
107+
// a nil value, and will instead offer to create the resource.
108+
if isNotFoundError(err) {
109+
return nil, nil
110+
}
111+
return nil, fmt.Errorf("failed to get connector with name %s: %w", name, err)
112+
}
113+
114+
// Bindplane should always return a connector but we should handle it
115+
// anyway considering we need to type assert it.
116+
switch c := r.(type) {
117+
case *model.Connector:
118+
return c, nil
119+
default:
120+
return nil, fmt.Errorf("unexpected response from bindplane, expected connector, got %T, this is a bug that should be reported", c)
121+
}
122+
}
123+
124+
// DeleteConnector will delete a BindPlane connector
125+
func (i *BindPlane) DeleteConnector(name string) error {
126+
err := i.Client.DeleteResource(context.Background(), model.KindConnector, name)
127+
if err != nil {
128+
return fmt.Errorf("error while deleting connector with name %s: %w", name, err)
129+
}
130+
return nil
131+
}
132+
101133
// Configuration takes a name and returns the matching configuration
102134
func (i *BindPlane) Configuration(name string) (*model.Configuration, error) {
103135
c, err := i.Client.Configuration(context.Background(), name)
@@ -231,6 +263,8 @@ func (i *BindPlane) Delete(k model.Kind, name string) error {
231263
return i.DeleteProcessor(name)
232264
case model.KindExtension:
233265
return i.DeleteExtension(name)
266+
case model.KindConnector:
267+
return i.DeleteConnector(name)
234268
default:
235269
return fmt.Errorf("Delete does not support bindplane kind '%s'", k)
236270
}
@@ -304,6 +338,20 @@ func (i *BindPlane) GenericResource(k model.Kind, name string) (*GenericResource
304338
return nil, nil
305339
}
306340

341+
g.ID = r.ID()
342+
g.Name = r.Name()
343+
g.Version = r.Version()
344+
g.Spec = r.Spec
345+
case model.KindConnector:
346+
r, err := i.Connector(name)
347+
if err != nil {
348+
return nil, err
349+
}
350+
351+
if r == nil {
352+
return nil, nil
353+
}
354+
307355
g.ID = r.ID()
308356
g.Name = r.Name()
309357
g.Version = r.Version()
Lines changed: 265 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,265 @@
1+
---
2+
subcategory: "Pipeline"
3+
description: |-
4+
A Configuration is a combination of sources, processors, and destinations
5+
used by BindPlane OP to generate an agent configuration.
6+
7+
Configuration V2 is the latest iteration of the BindPlane Configuration resource.
8+
It supports advanced routing and OpenTelemetry Connectors.
9+
---
10+
11+
> [!NOTE]
12+
> bindplane_configuration_v2 resources are supported by BindPlane OP version 1.85.0 and later.
13+
14+
# bindplane_configuration_v2
15+
16+
The `bindplane_configuration_v2` resource creates a BindPlane configuration that can be applied
17+
to one or more managed agents. Configurations are a combination of [sources](./bindplane_source.md),
18+
[destinations](./bindplane_destination.md), [processors](./bindplane_processor.md), and [connectors](./bindplane_connector.md).
19+
Explicit routes can be defined between components to control how telemetry data flows through the configuration.
20+
21+
Configuration V2 builds upon [Configuration V1](./bindplane_configuration.md) by introducing the following features:
22+
- **Routing**: Routes can be defined between all components. This allows for
23+
more granular control over how telemetry data flows through the configuration.
24+
- **Connectors**: [OpenTelemetry Connectors](https://github.com/open-telemetry/opentelemetry-collector/blob/main/connector/README.md)
25+
can be defined in the configuration. Connectors are used to route telemetry between pipelines, such as counting the number of logs
26+
and emitting a metric based on that count.
27+
- **Processors**: Processors can be defined in the configuration without attaching them directly to sources or destinations.
28+
This allows for more flexibility in how processors are used within a configuration. Processors can still be attached to sources
29+
or destinations just like before.
30+
31+
## Options
32+
33+
| Option | Type | Default | Description |
34+
| ------------------ | --------------- | -------- | --------------------------------------------------------------------------- |
35+
| `name` | string | required | The source name. |
36+
| `platform` | string | required | The platform the configuration supports. See the [supported platforms](./bindplane_configuration.md#supported-platforms) section. |
37+
| `labels` | map | optional | Key value pairs representing labels to set on the configuration. |
38+
| `source` | block | optional | One or more source blocks. See the [source block](./bindplane_configuration.md#source-block) section. |
39+
| `processor_group` | block | optional | One or more processor group blocks. See the [processor group block](./bindplane_configuration.md#processor-group-block) section. |
40+
| `destination` | block | optional | One or more destination blocks. See the [destination block](./bindplane_configuration.md#destination-block) section. |
41+
| `extensions` | list(string) | optional | One or more extension names to attach to the configuration. |
42+
| `rollout` | bool | required | Whether or not updates to the configuration should trigger an automatic rollout of the configuration. |
43+
| `rollout_options` | block (single) | optional | Options for configuring the rollout behavior of the configuration. See the [rollout options block](./bindplane_configuration.md#rollout-options-block) section. |
44+
45+
### Source Block
46+
47+
| Option | Type | Default | Description |
48+
| ------------------- | ------------ | -------- | ---------------------------- |
49+
| `name` | string | required | The source name. |
50+
| `processors` | list(string) | optional | One or more processor names to attach to the source. |
51+
| `route` | string | optional | One or more routes to attach to the source. See the [route block](./bindplane_configuration.md#route-block) section. |
52+
53+
### Processor Group Block
54+
55+
| Option | Type | Default | Description |
56+
| ------------------- | ------------ | -------- | ---------------------------- |
57+
| `route_id` | string | required | An arbitrary string that can be used to configure routes to this processor group. |
58+
| `processors` | list(string) | optional | One or more processor names to attach to the processor group. |
59+
| `route` | string | optional | One or more routes to attach to the processor group. See the [route block](./bindplane_configuration.md#route-block) section. |
60+
61+
### Destination Block
62+
63+
| Option | Type | Default | Description |
64+
| ------------------- | ------------ | -------- | ---------------------------- |
65+
| `route_id` | string | required | An arbitrary string that can be used to configure routes to this destination. |
66+
| `name` | string | required | The source name. |
67+
| `processors` | list(string) | optional | One or more processor names to attach to the destination. |
68+
69+
### Rollout Options Block
70+
71+
| Option | Type | Default | Description |
72+
| ------------------- | ------------ | -------- | ---------------------------- |
73+
| `type` | string | required | The type of rollout to perform. Valid values are 'standard' and 'progressive'. |
74+
| `parameters` | list(block) | optional | One or more parameters for the rollout. See the [parameters block](./bindplane_configuration.md#parameters-block) section. |
75+
76+
### Parameters Block
77+
78+
| Option | Type | Default | Description |
79+
| ------------------- | ------------ | -------- | ---------------------------- |
80+
| `name` | string | required | The name of the parameter. |
81+
| `value` | any | required | The value of the parameter. |
82+
83+
### Route Block
84+
85+
| Option | Type | Default | Description |
86+
| ------------------- | ------------ | -------- | ---------------------------- |
87+
| `route_id` | string | required | A unique string that identifies the route. |
88+
| `telemetry_type` | enum | `logs+metrics+traces` | The telemetry type to route. |
89+
| `components` | list(string) | required | One or more components to route the telemetry to. |
90+
91+
Telemetry types include the following
92+
- `logs`
93+
- `metrics`
94+
- `traces`
95+
- `logs+metrics`
96+
- `logs+traces`
97+
- `metrics+traces`
98+
- `logs+metrics+traces` (default)
99+
100+
The following example shows two route blocks, one for all telemetry types and one for traces only.
101+
102+
```tf
103+
# Route all telemetry types to the Datadog destination
104+
route {
105+
components = [
106+
"destinations/${bindplane_destination.datadog.id}"
107+
]
108+
}
109+
110+
# Route only traces to the Google destination
111+
route {
112+
telemetry_type = "traces"
113+
components = [
114+
"destinations/${bindplane_destination.google.id}"
115+
]
116+
}
117+
```
118+
119+
### Supported Platforms
120+
121+
This table should be used as a reference for supported `platform` values.
122+
123+
| Platform | Value |
124+
| ---------------------- | ----------------------- |
125+
| Linux | `linux` |
126+
| Windows | `windows` |
127+
| macOS | `macos` |
128+
| Kubernetes DaemonSet | `kubernetes-daemonset` |
129+
| Kubernetes Deployment | `kubernetes-deployment` |
130+
| OpenShift DaemonSet | `openshift-daemonset` |
131+
| OpenShift Deployment | `openshift-deployment` |
132+
133+
## Examples
134+
135+
This example shows the creation of a `bindplane_configuration_v2` which uses the following resources:
136+
- two [bindplane_source](./bindplane_source.md) resources
137+
- one [bindplane_destination](./bindplane_destination.md) resource
138+
- two [bindplane_processor](./bindplane_processor.md) resources
139+
140+
Routes are configured on the sources to send telemetry data to the destination.
141+
142+
```hcl
143+
resource "bindplane_source" "host" {
144+
rollout = true
145+
name = "my-host"
146+
type = "host"
147+
parameters_json = jsonencode(
148+
[
149+
{
150+
"name": "collection_interval",
151+
"value": 30
152+
},
153+
{
154+
"name": "enable_process",
155+
"value": false
156+
}
157+
]
158+
)
159+
}
160+
161+
resource "bindplane_source" "journald" {
162+
rollout = true
163+
name = "my-journald"
164+
type = "journald"
165+
}
166+
167+
resource "bindplane_destination" "google" {
168+
rollout = true
169+
name = "my-google"
170+
type = "googlecloud"
171+
}
172+
173+
resource "bindplane_processor" "batch" {
174+
rollout = true
175+
name = "my-batch"
176+
type = "batch"
177+
}
178+
179+
resource "bindplane_extension" "pprof" {
180+
rollout = true
181+
name = "my-pprof"
182+
type = "pprof"
183+
parameters_json = jsonencode(
184+
[
185+
{
186+
"name": "listen_address",
187+
"value": "0.0.0.0"
188+
},
189+
{
190+
"name": "tcp_port",
191+
"value": 5000,
192+
}
193+
]
194+
)
195+
}
196+
197+
resource "bindplane_configuration_v2" "configuration" {
198+
// When removing a component from a configuration and deleting that
199+
// component during the same apply, we want to update the configuration
200+
// before the component is deleted.
201+
lifecycle {
202+
create_before_destroy = true
203+
}
204+
205+
rollout = true
206+
name = "my-config"
207+
platform = "linux"
208+
labels = {
209+
environment = "production"
210+
managed-by = "terraform"
211+
}
212+
213+
source {
214+
name = bindplane_source.host.name
215+
route {
216+
components = [
217+
"destinations/${bindplane_destination.google.id}"
218+
]
219+
}
220+
}
221+
222+
source {
223+
name = bindplane_source.journald.name
224+
route {
225+
components = [
226+
"destinations/${bindplane_destination.google.id}"
227+
]
228+
}
229+
}
230+
231+
destination {
232+
name = bindplane_destination.google.name
233+
processors = [
234+
bindplane_processor.batch.name
235+
]
236+
}
237+
238+
extensions = [
239+
bindplane_extension.pprof.name
240+
]
241+
242+
rollout_options {
243+
type = "progressive"
244+
parameters = [
245+
{
246+
name = "stages"
247+
value = [
248+
{
249+
labels = {
250+
env = "stage"
251+
}
252+
name = "stage"
253+
},
254+
{
255+
labels = {
256+
env = "production"
257+
}
258+
name = "production"
259+
}
260+
]
261+
}
262+
]
263+
}
264+
}
265+
```

0 commit comments

Comments
 (0)