Skip to content

Commit 08aa89b

Browse files
committed
Merge branch 'update-docker-compose-example' of github.com:grafana/agent into update-docker-compose-example
2 parents d44d10e + 6cc21e4 commit 08aa89b

File tree

5 files changed

+358
-2
lines changed

5 files changed

+358
-2
lines changed

CHANGELOG.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,12 @@ Main (unreleased)
2323

2424
- New Grafana Agent Flow components:
2525

26-
- `prometheus.exporter.gcp` - scrape GCP metrics (@tburgessdev)
26+
- `prometheus.exporter.gcp` - scrape GCP metrics. (@tburgessdev)
2727
- `otelcol.processor.span` - accepts traces telemetry data from other `otelcol`
2828
components and modifies the names and attributes of the spans. (@ptodev)
29-
- `discovery.uyuni` discovers scrape targets from a Uyuni Server. (@spartan0x117)
29+
- `discovery.uyuni` discovers scrape targets from a Uyuni Server. (@sparta0x117)
3030
- `discovery.eureka` discovers targets from a Eureka Service Registry. (@spartan0x117)
31+
- `discovery.openstack` - service discovery for OpenStack. (@marctc)
3132

3233
### Bugfixes
3334

component/all/all.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import (
1515
_ "github.com/grafana/agent/component/discovery/kubelet" // Import discovery.kubelet
1616
_ "github.com/grafana/agent/component/discovery/kubernetes" // Import discovery.kubernetes
1717
_ "github.com/grafana/agent/component/discovery/nomad" // Import discovery.nomad
18+
_ "github.com/grafana/agent/component/discovery/openstack" // Import discovery.openstack
1819
_ "github.com/grafana/agent/component/discovery/relabel" // Import discovery.relabel
1920
_ "github.com/grafana/agent/component/discovery/uyuni" // Import discovery.uyuni
2021
_ "github.com/grafana/agent/component/local/file" // Import local.file
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
package openstack
2+
3+
import (
4+
"fmt"
5+
"time"
6+
7+
"github.com/grafana/agent/component"
8+
"github.com/grafana/agent/component/common/config"
9+
"github.com/grafana/agent/component/discovery"
10+
"github.com/grafana/agent/pkg/river/rivertypes"
11+
config_util "github.com/prometheus/common/config"
12+
"github.com/prometheus/common/model"
13+
prom_discovery "github.com/prometheus/prometheus/discovery/openstack"
14+
)
15+
16+
func init() {
17+
component.Register(component.Registration{
18+
Name: "discovery.openstack",
19+
Args: Arguments{},
20+
Exports: discovery.Exports{},
21+
22+
Build: func(opts component.Options, args component.Arguments) (component.Component, error) {
23+
return New(opts, args.(Arguments))
24+
},
25+
})
26+
}
27+
28+
type Arguments struct {
29+
IdentityEndpoint string `river:"identity_endpoint,attr,optional"`
30+
Username string `river:"username,attr,optional"`
31+
UserID string `river:"userid,attr,optional"`
32+
Password rivertypes.Secret `river:"password,attr,optional"`
33+
ProjectName string `river:"project_name,attr,optional"`
34+
ProjectID string `river:"project_id,attr,optional"`
35+
DomainName string `river:"domain_name,attr,optional"`
36+
DomainID string `river:"domain_id,attr,optional"`
37+
ApplicationCredentialName string `river:"application_credential_name,attr,optional"`
38+
ApplicationCredentialID string `river:"application_credential_id,attr,optional"`
39+
ApplicationCredentialSecret rivertypes.Secret `river:"application_credential_secret,attr,optional"`
40+
Role string `river:"role,attr"`
41+
Region string `river:"region,attr"`
42+
RefreshInterval time.Duration `river:"refresh_interval,attr,optional"`
43+
Port int `river:"port,attr,optional"`
44+
AllTenants bool `river:"all_tenants,attr,optional"`
45+
TLSConfig config.TLSConfig `river:"tls_config,attr,optional"`
46+
Availability string `river:"availability,attr,optional"`
47+
}
48+
49+
var DefaultArguments = Arguments{
50+
Port: 80,
51+
RefreshInterval: time.Duration(60),
52+
Availability: "public",
53+
}
54+
55+
// SetToDefault implements river.Defaulter.
56+
func (args *Arguments) SetToDefault() {
57+
*args = DefaultArguments
58+
}
59+
60+
// Validate implements river.Validator.
61+
func (args *Arguments) Validate() error {
62+
switch args.Availability {
63+
case "public", "internal", "admin":
64+
default:
65+
return fmt.Errorf("unknown availability %s, must be one of admin, internal or public", args.Availability)
66+
}
67+
68+
switch args.Role {
69+
case "instance", "hypervisor":
70+
default:
71+
return fmt.Errorf("unknown availability %s, must be one of instance or hypervisor", args.Role)
72+
}
73+
return args.TLSConfig.Validate()
74+
}
75+
76+
func (args *Arguments) Convert() *prom_discovery.SDConfig {
77+
tlsConfig := &args.TLSConfig
78+
79+
return &prom_discovery.SDConfig{
80+
IdentityEndpoint: args.IdentityEndpoint,
81+
Username: args.Username,
82+
UserID: args.UserID,
83+
Password: config_util.Secret(args.Password),
84+
ProjectName: args.ProjectName,
85+
ProjectID: args.ProjectID,
86+
DomainName: args.DomainName,
87+
DomainID: args.DomainID,
88+
ApplicationCredentialName: args.ApplicationCredentialName,
89+
ApplicationCredentialID: args.ApplicationCredentialID,
90+
ApplicationCredentialSecret: config_util.Secret(args.ApplicationCredentialSecret),
91+
Role: prom_discovery.Role(args.Role),
92+
Region: args.Region,
93+
RefreshInterval: model.Duration(args.RefreshInterval),
94+
Port: args.Port,
95+
AllTenants: args.AllTenants,
96+
TLSConfig: *tlsConfig.Convert(),
97+
Availability: args.Availability,
98+
}
99+
}
100+
101+
// New returns a new instance of a discovery.openstack component.
102+
func New(opts component.Options, args Arguments) (*discovery.Component, error) {
103+
return discovery.New(opts, args, func(args component.Arguments) (discovery.Discoverer, error) {
104+
newArgs := args.(Arguments)
105+
return prom_discovery.NewDiscovery(newArgs.Convert(), opts.Logger)
106+
})
107+
}
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
package openstack
2+
3+
import (
4+
"testing"
5+
"time"
6+
7+
"github.com/grafana/agent/pkg/river"
8+
"github.com/prometheus/common/config"
9+
"github.com/prometheus/common/model"
10+
"github.com/prometheus/prometheus/discovery/openstack"
11+
"github.com/stretchr/testify/require"
12+
)
13+
14+
func TestUnmarshal(t *testing.T) {
15+
cfg := `
16+
identity_endpoint = "http://openstack"
17+
username = "exampleuser"
18+
userid = "exampleuserid"
19+
password = "examplepassword"
20+
project_name = "exampleproject"
21+
project_id = "exampleprojectid"
22+
domain_name = "exampledomain"
23+
domain_id = "exampledomainid"
24+
application_credential_name = "exampleappcred"
25+
application_credential_id = "exampleappcredid"
26+
role = "hypervisor"
27+
region = "us-east-1"
28+
refresh_interval = "1m"
29+
port = 80
30+
all_tenants = true
31+
`
32+
var args Arguments
33+
err := river.Unmarshal([]byte(cfg), &args)
34+
require.NoError(t, err)
35+
}
36+
37+
func TestValidate(t *testing.T) {
38+
wrongAvailability := `
39+
role = "hypervisor"
40+
region = "us-east-1"
41+
availability = "private"`
42+
43+
var args Arguments
44+
err := river.Unmarshal([]byte(wrongAvailability), &args)
45+
require.ErrorContains(t, err, "unknown availability private, must be one of admin, internal or public")
46+
47+
wrongRole := `
48+
role = "private"
49+
region = "us-east-1"
50+
availability = "public"`
51+
52+
var args2 Arguments
53+
err = river.Unmarshal([]byte(wrongRole), &args2)
54+
require.ErrorContains(t, err, "unknown availability private, must be one of instance or hypervisor")
55+
}
56+
57+
func TestConvert(t *testing.T) {
58+
args := Arguments{
59+
IdentityEndpoint: "http://openstack",
60+
Username: "exampleuser",
61+
UserID: "exampleuserid",
62+
Password: "examplepassword",
63+
ProjectName: "exampleproject",
64+
ProjectID: "exampleprojectid",
65+
DomainName: "exampledomain",
66+
DomainID: "exampledomainid",
67+
ApplicationCredentialName: "exampleappcred",
68+
ApplicationCredentialID: "exampleappcredid",
69+
Role: "hypervisor",
70+
Region: "us-east-1",
71+
RefreshInterval: time.Duration(60),
72+
Port: 80,
73+
AllTenants: true,
74+
Availability: "public",
75+
}
76+
converted := args.Convert()
77+
78+
require.Equal(t, "http://openstack", converted.IdentityEndpoint)
79+
require.Equal(t, "exampleuser", converted.Username)
80+
require.Equal(t, "exampleuserid", converted.UserID)
81+
require.Equal(t, config.Secret("examplepassword"), converted.Password)
82+
require.Equal(t, "exampleproject", converted.ProjectName)
83+
require.Equal(t, "exampleprojectid", converted.ProjectID)
84+
require.Equal(t, "exampledomain", converted.DomainName)
85+
require.Equal(t, "exampledomainid", converted.DomainID)
86+
require.Equal(t, "exampleappcred", converted.ApplicationCredentialName)
87+
require.Equal(t, "exampleappcredid", converted.ApplicationCredentialID)
88+
require.Equal(t, openstack.Role("hypervisor"), converted.Role)
89+
require.Equal(t, "us-east-1", converted.Region)
90+
require.Equal(t, model.Duration(60), converted.RefreshInterval)
91+
require.Equal(t, 80, converted.Port)
92+
require.Equal(t, true, converted.AllTenants)
93+
require.Equal(t, "public", converted.Availability)
94+
}
Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
---
2+
canonical: https://grafana.com/docs/agent/latest/flow/reference/components/discovery.openstack/
3+
title: discovery.openstack
4+
---
5+
6+
# discovery.openstack
7+
8+
`discovery.openstack` discovers [OpenStack][] Nova instances and exposes them as targets.
9+
10+
[OpenStack]: https://docs.openstack.org/nova/latest/
11+
12+
## Usage
13+
14+
```river
15+
discovery.openstack "LABEL" {
16+
role = "hypervisor"
17+
region = "us-east-1"
18+
}
19+
```
20+
21+
## Arguments
22+
23+
The following arguments are supported:
24+
25+
Name | Type | Description | Default | Required
26+
------------------- | ---------- | ---------------------------------------------------------------------- | -------------------- | --------
27+
`role` | `string` | Role of the discovered targets. | | yes
28+
`region` | `string` | OpenStack region. | | yes
29+
`identity_endpoint` | `string` | Specifies the HTTP endpoint that is required to work with te Identity API of the appropriate version | | no
30+
`username` | `string` | OpenStack username for the Identity V2 and V3 APIs. | | no
31+
`userid` | `string` | OpenStack userid for the Identity V2 and V3 APIs. | | no
32+
`password` | `secret` | Password for the Identity V2 and V3 APIs. | | no
33+
`domain_name` | `string` | OpenStack domain name for the Identity V2 and V3 APIs. | | no
34+
`domain_id` | `string` | OpenStack domain ID for the Identity V2 and V3 APIs. | | no
35+
`project_name` | `string` | OpenStack project name for the Identity V2 and V3 APIs. | | no
36+
`project_id` | `string` | OpenStack project ID for the Identity V2 and V3 APIs. | | no
37+
`application_credential_name` | `string` | OpenStack application credential name for the Identity V2 and V3 APIs. | | no
38+
`application_credential_id` | `string` | OpenStack application credential ID for the Identity V2 and V3 APIs. | | no
39+
`application_credential_secret` | `secret` | OpenStack application credential secret for the Identity V2 and V3 APIs. | | no
40+
`all_tenants` | `bool` | Whether the service discovery should list all instances for all projects. | `false` | no
41+
`refresh_interval` | `duration`| Refresh interval to re-read the instance list. | `60s` | no
42+
`port` | `int` | The port to scrape metrics from. | `80` | no
43+
`availability` | `string` | The availability of the endpoint to connect to. | `public` | no
44+
45+
`role` must be one of `hypervisor` or `instance`.
46+
47+
`username` is required if using Identity V2 API. In Identity V3, either `userid` or a combination of `username` and `domain_id` or `domain_name` are needed.
48+
49+
`project_id` and `project_name` fields are optional for the Identity V2 API. Some providers allow you to specify a `project_name` instead of the `project_id`. Some require both.
50+
51+
`application_credential_id` or `application_credential_name` fields are required if using an application credential to authenticate. Some providers allow you to create an application credential to authenticate rather than a password.
52+
53+
`application_credential_secret` field is required if using an application credential to authenticate.
54+
55+
`all_tenants` is only relevant for the `instance` role and usually requires admin permissions.
56+
57+
`availability` must be one of `public`, `admin`, or `internal`.
58+
59+
## Blocks
60+
The following blocks are supported inside the definition of `discovery.openstack`:
61+
62+
Hierarchy | Block | Description | Required
63+
--------- | ----- | ----------- | --------
64+
tls_config | [tls_config][] | TLS configuration for requests to the OpenStack API. | no
65+
66+
[tls_config]: #tls_config-block
67+
68+
### tls_config block
69+
70+
{{< docs/shared lookup="flow/reference/components/tls-config-block.md" source="agent" >}}
71+
72+
## Exported fields
73+
74+
The following fields are exported and can be referenced by other components:
75+
76+
Name | Type | Description
77+
--------- | ------------------- | -----------
78+
`targets` | `list(map(string))` | The set of targets discovered from the OpenStack API.
79+
80+
#### `hypervisor`
81+
82+
The `hypervisor` role discovers one target per Nova hypervisor node. The target
83+
address defaults to the `host_ip` attribute of the hypervisor.
84+
85+
* `__meta_openstack_hypervisor_host_ip`: the hypervisor node's IP address.
86+
* `__meta_openstack_hypervisor_hostname`: the hypervisor node's name.
87+
* `__meta_openstack_hypervisor_id`: the hypervisor node's ID.
88+
* `__meta_openstack_hypervisor_state`: the hypervisor node's state.
89+
* `__meta_openstack_hypervisor_status`: the hypervisor node's status.
90+
* `__meta_openstack_hypervisor_type`: the hypervisor node's type.
91+
92+
#### `instance`
93+
94+
The `instance` role discovers one target per network interface of Nova
95+
instance. The target address defaults to the private IP address of the network
96+
interface.
97+
98+
* `__meta_openstack_address_pool`: the pool of the private IP.
99+
* `__meta_openstack_instance_flavor`: the flavor of the OpenStack instance.
100+
* `__meta_openstack_instance_id`: the OpenStack instance ID.
101+
* `__meta_openstack_instance_image`: the ID of the image the OpenStack instance is using.
102+
* `__meta_openstack_instance_name`: the OpenStack instance name.
103+
* `__meta_openstack_instance_status`: the status of the OpenStack instance.
104+
* `__meta_openstack_private_ip`: the private IP of the OpenStack instance.
105+
* `__meta_openstack_project_id`: the project (tenant) owning this instance.
106+
* `__meta_openstack_public_ip`: the public IP of the OpenStack instance.
107+
* `__meta_openstack_tag_<tagkey>`: each tag value of the instance.
108+
* `__meta_openstack_user_id`: the user account owning the tenant.
109+
110+
## Component health
111+
112+
`discovery.openstack` is only reported as unhealthy when given an invalid
113+
configuration. In those cases, exported fields retain their last healthy
114+
values.
115+
116+
## Debug information
117+
118+
`discovery.openstack` does not expose any component-specific debug information.
119+
120+
### Debug metrics
121+
122+
`discovery.openstack` does not expose any component-specific debug metrics.
123+
124+
## Example
125+
126+
```river
127+
discovery.openstack "example" {
128+
role = OPENSTACK_ROLE
129+
region = OPENSTACK_REGION
130+
}
131+
132+
prometheus.scrape "demo" {
133+
targets = discovery.openstack.example.targets
134+
forward_to = [prometheus.remote_write.demo.receiver]
135+
}
136+
137+
prometheus.remote_write "demo" {
138+
endpoint {
139+
url = PROMETHEUS_REMOTE_WRITE_URL
140+
141+
basic_auth {
142+
username = USERNAME
143+
password = PASSWORD
144+
}
145+
}
146+
}
147+
```
148+
Replace the following:
149+
- `OPENSTACK_ROLE`: Your OpenStack role.
150+
- `OPENSTACK_REGION`: Your OpenStack region.
151+
- `PROMETHEUS_REMOTE_WRITE_URL`: The URL of the Prometheus remote_write-compatible server to send metrics to.
152+
- `USERNAME`: The username to use for authentication to the remote_write API.
153+
- `PASSWORD`: The password to use for authentication to the remote_write API.

0 commit comments

Comments
 (0)