Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SNMP exporter: Use a "name" argument for "target" and "walk_param" blocks #1790

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ Main (unreleased)
- The `mimir.rules.kubernetes` component now supports adding extra label matchers
to all queries discovered via `PrometheusRule` CRDs. (@thampiotr)

- `prometheus.exporter.snmp`: The names of `target` and `walk_param` blocks can now be set
via an argument instead of block label. The block label syntax for
the `target` and `walk_param` blocks will be removed in Alloy 2.0. (@ptodev)

### Bugfixes

- Update windows_exporter from v0.27.2 vo v0.27.3: (@jkroepke)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ The `prometheus.exporter.snmp` component embeds
prometheus.exporter.snmp "LABEL" {
config_file = SNMP_CONFIG_FILE_PATH

target "TARGET_NAME" {
target {
name = TARGET_NAME
address = TARGET_ADDRESS
}
}
Expand All @@ -48,7 +49,7 @@ Omitted fields take their default values.
| `targets` | `list(map(string))` | SNMP targets. | | no |

The `config_file` argument points to a YAML file defining which snmp_exporter modules to use.
Refer to [snmp_exporter](https://github.com/prometheus/snmp_exporter#generating-configuration) for details on how to generate a configuration file.
Refer to [snmp_exporter][snmp_exporter-cfg] for details on how to generate a configuration file.

The `config` argument must be a YAML document as string defining which SNMP modules and auths to use.
`config` is typically loaded by using the exports of another component. For example,
Expand All @@ -65,6 +66,8 @@ The following labels can be set to a target:
* `auth`: The SNMP authentication profile to use.
* `walk_params`: The config to use for this target.

[snmp_exporter-cfg]: https://github.com/prometheus/snmp_exporter#generating-configuration

## Blocks

The following blocks are supported inside the definition of
Expand All @@ -81,28 +84,43 @@ The following blocks are supported inside the definition of
### target block

The `target` block defines an individual SNMP target.
The `target` block may be specified multiple times to define multiple targets. The label of the block is required and will be used in the target's `job` label.
The `target` block may be specified multiple times to define multiple targets.

| Name | Type | Description | Default | Required |
| -------------- | -------- | --------------------------------------------------------------------- | ------- | -------- |
| `name` | `string` | The name of the target. | | yes |
| `address` | `string` | The address of SNMP device. | | yes |
| `module` | `string` | SNMP module to use for polling. | `""` | no |
| `auth` | `string` | SNMP authentication profile to use. | `""` | no |
| `walk_params` | `string` | Config to use for this target. | `""` | no |
| `snmp_context` | `string` | Override the `context_name` parameter in the SNMP configuration file. | `""` | no |

The value of the `name` argument will be set as the value of the target's `job` label.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
The value of the `name` argument will be set as the value of the target's `job` label.
The value of the `name` argument is set to the value of the target's `job` label.


{{< admonition type="note" >}}
Instead of a `name` argument, previous versions of Alloy used to use a block label.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Instead of a `name` argument, previous versions of Alloy used to use a block label.
Instead of a `name` argument, previous versions of {{< param "PRODUCT_NAME" >}} used a block label.

See the [Deprecated features](#deprecated-features) section for more information.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
See the [Deprecated features](#deprecated-features) section for more information.
Refer to [Deprecated features](#deprecated-features) for more information.

{{< /admonition >}}

If `name` is not set, the target's `job` label will be set to the label of the `target` block.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
If `name` is not set, the target's `job` label will be set to the label of the `target` block.
If `name` is not set, the target's `job` label is set to the label of the `target` block.


### walk_param block

The `walk_param` block defines an individual SNMP connection profile that can be used to override default SNMP settings.
The `walk_param` block may be specified multiple times to define multiple SNMP connection profiles.

| Name | Type | Description | Default | Required |
| ----------------- | ---------- | --------------------------------------------- | ------- | -------- |
| `name` | `string` | Name of the module to override. | | no |
| `name` | `string` | Name of the module to override. | | yes |
| `max_repetitions` | `int` | How many objects to request with GET/GETBULK. | `25` | no |
| `retries` | `int` | How many times to retry a failed request. | `3` | no |
| `timeout` | `duration` | Timeout for each individual SNMP request. | | no |

{{< admonition type="note" >}}
Instead of a `name` argument, previous versions of Alloy used to use a block label.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Instead of a `name` argument, previous versions of Alloy used to use a block label.
Instead of a `name` argument, previous versions of {{< param "PRODUCT_NAME" >}} used a block label.

See the [Deprecated features](#deprecated-features) section for more information.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
See the [Deprecated features](#deprecated-features) section for more information.
Refer to [Deprecated features](#deprecated-features) for more information.

{{< /admonition >}}

## Exported fields

{{< docs/shared lookup="reference/components/exporter-component-exports.md" source="alloy" version="<ALLOY_VERSION>" >}}
Expand All @@ -123,6 +141,46 @@ debug information.
`prometheus.exporter.snmp` does not expose any component-specific
debug metrics.

## Deprecated features

In previous versions of Alloy, the names `target` blocks and `walk_param` blocks were specified via a block label:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
In previous versions of Alloy, the names `target` blocks and `walk_param` blocks were specified via a block label:
In previous versions of {{< param "PRODUCT_NAME" >}}, the names `target` blocks and `walk_param` blocks were specified via a block label:


```alloy
target "example_name_of_target" {
...
}

walk_param "example_name_of_walk_param" {
...
}
```

Users are now advised to switch to using a `name` attribute instead:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Users are now advised to switch to using a `name` attribute instead:
You can switch to using a `name` attribute instead of using a block label:


```alloy
target {
name = "example_name_of_target"
...
}

walk_param {
name = "example_name_of_walk_param"
...
}
```

Block labels for `target` and `walk_param` are deprecated and will be removed in version 2.0 of Alloy.
In Alloy version 1, it will remain possible to use a block label instead of the `name` attribute.
However, the `name` attribute is documented as "required" to encourage users to use it and to remove confusion.
Comment on lines +172 to +174
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Block labels for `target` and `walk_param` are deprecated and will be removed in version 2.0 of Alloy.
In Alloy version 1, it will remain possible to use a block label instead of the `name` attribute.
However, the `name` attribute is documented as "required" to encourage users to use it and to remove confusion.
Block labels for `target` and `walk_param` are deprecated and will be removed in {{< param "PRODUCT_NAME" >}} 2.0.
In {{< param "PRODUCT_NAME" >}} 1.x, you can continue to use a block label.
However, the `name` attribute is documented as "required" to encourage users to use it and to remove confusion.

What happens if the user keeps the block labels AND adds a name attribute?


The benefits of using a `name` attribute include:
* Not being subject to restrictions on [Alloy Syntax Identifiers][syntax-identifiers].
* It is possible to get the value of a `name` argument from a component such as [local.file][] or [remote.http][].
Comment on lines +176 to +178
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
The benefits of using a `name` attribute include:
* Not being subject to restrictions on [Alloy Syntax Identifiers][syntax-identifiers].
* It is possible to get the value of a `name` argument from a component such as [local.file][] or [remote.http][].
The benefits of using a `name` attribute include:
* You aren't subject to restrictions on [Alloy Syntax Identifiers][syntax-identifiers].
* You can get the value of a `name` argument from a component such as [local.file][] or [remote.http][].


[syntax-identifiers]: ../../../../get-started/configuration-syntax/syntax/#identifiers
[local.file]: ../../local.file
[remote.http]: ../../remote.http

## Example

This example uses a [`prometheus.scrape` component][scrape] to collect metrics
Expand All @@ -132,23 +190,27 @@ from `prometheus.exporter.snmp`:
prometheus.exporter.snmp "example" {
config_file = "snmp_modules.yml"

target "network_switch_1" {
target {
name = "network_switch_1"
address = "192.168.1.2"
module = "if_mib"
walk_params = "public"
}

target "network_router_2" {
target {
name = "network_router_2"
address = "192.168.1.3"
module = "mikrotik"
walk_params = "private"
}

walk_param "private" {
walk_param {
name = "private"
retries = "2"
}

walk_param "public" {
walk_param {
name = "public"
retries = "2"
}
}
Expand All @@ -171,23 +233,27 @@ local.file "snmp_config" {
prometheus.exporter.snmp "example" {
config = local.file.snmp_config.content

target "network_switch_1" {
target {
name = "network_switch_1"
address = "192.168.1.2"
module = "if_mib"
walk_params = "public"
}

target "network_router_2" {
target {
name = "network_router_2"
address = "192.168.1.3"
module = "mikrotik"
walk_params = "private"
}

walk_param "private" {
walk_param {
name = "private"
retries = "2"
}

walk_param "public" {
walk_param {
name = "public"
retries = "2"
}
}
Expand Down Expand Up @@ -236,11 +302,13 @@ prometheus.exporter.snmp "example" {
},
]

walk_param "private" {
walk_param {
name = "private"
retries = "2"
}

walk_param "public" {
walk_param {
name = "public"
retries = "2"
}
}
Expand All @@ -264,11 +332,13 @@ prometheus.exporter.snmp "example" {

targets = encoding.from_yaml(local.file.targets.content)

walk_param "private" {
walk_param {
name = "private"
retries = "2"
}

walk_param "public" {
walk_param {
name = "public"
retries = "2"
}
}
Expand Down
2 changes: 1 addition & 1 deletion internal/cmd/alloylint/internal/syntaxtags/syntaxtags.go
Original file line number Diff line number Diff line change
Expand Up @@ -279,7 +279,7 @@ func lintSyntaxTag(ty *types.Var, tag string) (diagnostics []string) {
}
}

case "label":
case "label", "label,optional":
if name != "" {
diagnostics = append(diagnostics, "label field must have an empty value for name")
}
Expand Down
66 changes: 60 additions & 6 deletions internal/component/prometheus/exporter/snmp/snmp.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ func buildSNMPTargets(baseTarget discovery.Target, args component.Arguments) []d
target[k] = v
}

target["job"] = target["job"] + "/" + tgt.Name
target["job"] = target["job"] + "/" + tgt.Name()
target["__param_target"] = tgt.Target
if tgt.Module != "" {
target["__param_module"] = tgt.Module
Expand All @@ -71,7 +71,9 @@ func buildSNMPTargets(baseTarget discovery.Target, args component.Arguments) []d

// SNMPTarget defines a target to be used by the exporter.
type SNMPTarget struct {
Name string `alloy:",label"`
//TODO: For Alloy 2.0: Remove NameLbl and make NameArg mandatory.
NameLbl string `alloy:",label,optional"`
NameArg string `alloy:"name,attr,optional"`
Target string `alloy:"address,attr"`
Module string `alloy:"module,attr,optional"`
Auth string `alloy:"auth,attr,optional"`
Expand All @@ -86,7 +88,7 @@ func (t TargetBlock) Convert() []snmp_exporter.SNMPTarget {
targets := make([]snmp_exporter.SNMPTarget, 0, len(t))
for _, target := range t {
targets = append(targets, snmp_exporter.SNMPTarget{
Name: target.Name,
Name: target.Name(),
Target: target.Target,
Module: target.Module,
Auth: target.Auth,
Expand All @@ -97,8 +99,25 @@ func (t TargetBlock) Convert() []snmp_exporter.SNMPTarget {
return targets
}

// Name() assumes that either NameLbl or NameArg is set.
// It also that both NameLbl and NameArg are not set at the same time,
// as this is checked during unmarshalling.
func (t *SNMPTarget) Name() string {
if t == nil {
return ""
}

if len(t.NameArg) > 0 {
return t.NameArg
}

return t.NameLbl
}

type WalkParam struct {
Name string `alloy:",label"`
//TODO: For Alloy 2.0: Remove NameLbl and make NameArg mandatory.
NameLbl string `alloy:",label,optional"`
NameArg string `alloy:"name,attr,optional"`
MaxRepetitions uint32 `alloy:"max_repetitions,attr,optional"`
Retries int `alloy:"retries,attr,optional"`
Timeout time.Duration `alloy:"timeout,attr,optional"`
Expand All @@ -111,7 +130,7 @@ type WalkParams []WalkParam
func (w WalkParams) Convert() map[string]snmp_config.WalkParams {
walkParams := make(map[string]snmp_config.WalkParams)
for _, walkParam := range w {
walkParams[walkParam.Name] = snmp_config.WalkParams{
walkParams[walkParam.Name()] = snmp_config.WalkParams{
MaxRepetitions: walkParam.MaxRepetitions,
Retries: &walkParam.Retries,
Timeout: walkParam.Timeout,
Expand All @@ -121,6 +140,21 @@ func (w WalkParams) Convert() map[string]snmp_config.WalkParams {
return walkParams
}

// Name() assumes that either NameLbl or NameArg is set.
// It also that both NameLbl and NameArg are not set at the same time,
// as this is checked during unmarshalling.
func (p *WalkParam) Name() string {
if p == nil {
return ""
}

if len(p.NameArg) > 0 {
return p.NameArg
}

return p.NameLbl
}

type Arguments struct {
ConfigFile string `alloy:"config_file,attr,optional"`
Config alloytypes.OptionalSecret `alloy:"config,attr,optional"`
Expand Down Expand Up @@ -155,7 +189,7 @@ func (t TargetsList) convert() []SNMPTarget {
for _, target := range t {
address, _ := getAddress(target)
targets = append(targets, SNMPTarget{
Name: target["name"],
NameArg: target["name"],
Target: address,
Module: target["module"],
Auth: target["auth"],
Expand All @@ -181,6 +215,26 @@ func (a *Arguments) UnmarshalAlloy(f func(interface{}) error) error {
return fmt.Errorf("the block `target` and the attribute `targets` are mutually exclusive")
}

for _, walkParam := range a.WalkParams {
if walkParam.NameArg != "" && walkParam.NameLbl != "" {
return errors.New("the label of a `walk_param` block and the `name` argument are mutually exclusive")
}

if walkParam.NameArg == "" && walkParam.NameLbl == "" {
return errors.New("either the label of a `walk_param` block or the `name` argument must be set")
}
}

for _, target := range a.Targets {
if target.NameArg != "" && target.NameLbl != "" {
return errors.New("the label of a `target` block and the `name` argument are mutually exclusive")
}

if target.NameArg == "" && target.NameLbl == "" {
return errors.New("either the label of a `target` block or the `name` argument must be set")
}
}

for _, target := range a.TargetsList {
if _, hasName := target["name"]; !hasName {
return fmt.Errorf("all targets must have a `name`")
Expand Down
Loading
Loading