fix(STACKITTPR-168): improve error messages (#762)

* remove deprecated argus resources

* improve error messages
This commit is contained in:
Marcel Jacek 2025-04-04 14:18:16 +02:00 committed by GitHub
parent 1c02c5eb67
commit d6749b6ce3
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
76 changed files with 600 additions and 8403 deletions

View file

@ -1,154 +0,0 @@
---
# generated by https://github.com/hashicorp/terraform-plugin-docs
page_title: "stackit_argus_instance Data Source - stackit"
subcategory: ""
description: |-
Argus instance data source schema. Must have a region specified in the provider configuration.
!> The stackit_argus_instance data source has been deprecated and will be removed after February 26th 2025. Please use stackit_observability_instance instead, which offers the exact same functionality.
---
# stackit_argus_instance (Data Source)
Argus instance data source schema. Must have a `region` specified in the provider configuration.
!> The `stackit_argus_instance` data source has been deprecated and will be removed after February 26th 2025. Please use `stackit_observability_instance` instead, which offers the exact same functionality.
## Example Usage
```terraform
data "stackit_argus_instance" "example" {
project_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
instance_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
}
```
<!-- schema generated by tfplugindocs -->
## Schema
### Required
- `instance_id` (String) The Argus instance ID.
- `project_id` (String) STACKIT project ID to which the instance is associated.
### Read-Only
- `acl` (Set of String) The access control list for this instance. Each entry is an IP address range that is permitted to access, in CIDR notation.
- `alert_config` (Attributes) Alert configuration for the instance. (see [below for nested schema](#nestedatt--alert_config))
- `alerting_url` (String) Specifies Alerting URL.
- `dashboard_url` (String) Specifies Argus instance dashboard URL.
- `grafana_initial_admin_password` (String, Sensitive) Specifies an initial Grafana admin password.
- `grafana_initial_admin_user` (String) Specifies an initial Grafana admin username.
- `grafana_public_read_access` (Boolean) If true, anyone can access Grafana dashboards without logging in.
- `grafana_url` (String) Specifies Grafana URL.
- `id` (String) Terraform's internal data source ID. It is structured as "`project_id`,`instance_id`".
- `is_updatable` (Boolean) Specifies if the instance can be updated.
- `jaeger_traces_url` (String)
- `jaeger_ui_url` (String)
- `logs_push_url` (String) Specifies URL for pushing logs.
- `logs_url` (String) Specifies Logs URL.
- `metrics_push_url` (String) Specifies URL for pushing metrics.
- `metrics_retention_days` (Number) Specifies for how many days the raw metrics are kept.
- `metrics_retention_days_1h_downsampling` (Number) Specifies for how many days the 1h downsampled metrics are kept. must be less than the value of the 5m downsampling retention. Default is set to `0` (disabled).
- `metrics_retention_days_5m_downsampling` (Number) Specifies for how many days the 5m downsampled metrics are kept. must be less than the value of the general retention. Default is set to `0` (disabled).
- `metrics_url` (String) Specifies metrics URL.
- `name` (String) The name of the Argus instance.
- `otlp_traces_url` (String)
- `parameters` (Map of String) Additional parameters.
- `plan_id` (String) The Argus plan ID.
- `plan_name` (String) Specifies the Argus plan. E.g. `Monitoring-Medium-EU01`.
- `targets_url` (String) Specifies Targets URL.
- `zipkin_spans_url` (String)
<a id="nestedatt--alert_config"></a>
### Nested Schema for `alert_config`
Read-Only:
- `global` (Attributes) Global configuration for the alerts. (see [below for nested schema](#nestedatt--alert_config--global))
- `receivers` (Attributes List) List of alert receivers. (see [below for nested schema](#nestedatt--alert_config--receivers))
- `route` (Attributes) The route for the alert. (see [below for nested schema](#nestedatt--alert_config--route))
<a id="nestedatt--alert_config--global"></a>
### Nested Schema for `alert_config.global`
Read-Only:
- `opsgenie_api_key` (String, Sensitive) The API key for OpsGenie.
- `opsgenie_api_url` (String) The host to send OpsGenie API requests to. Must be a valid URL
- `resolve_timeout` (String) The default value used by alertmanager if the alert does not include EndsAt. After this time passes, it can declare the alert as resolved if it has not been updated. This has no impact on alerts from Prometheus, as they always include EndsAt.
- `smtp_auth_identity` (String) SMTP authentication information. Must be a valid email address
- `smtp_auth_password` (String, Sensitive) SMTP Auth using LOGIN and PLAIN.
- `smtp_auth_username` (String) SMTP Auth using CRAM-MD5, LOGIN and PLAIN. If empty, Alertmanager doesn't authenticate to the SMTP server.
- `smtp_from` (String) The default SMTP From header field. Must be a valid email address
- `smtp_smart_host` (String) The default SMTP smarthost used for sending emails, including port number. Port number usually is 25, or 587 for SMTP over TLS (sometimes referred to as STARTTLS).
<a id="nestedatt--alert_config--receivers"></a>
### Nested Schema for `alert_config.receivers`
Read-Only:
- `email_configs` (Attributes List) List of email configurations. (see [below for nested schema](#nestedatt--alert_config--receivers--email_configs))
- `name` (String) Name of the receiver.
- `opsgenie_configs` (Attributes List) List of OpsGenie configurations. (see [below for nested schema](#nestedatt--alert_config--receivers--opsgenie_configs))
- `webhooks_configs` (Attributes List) List of Webhooks configurations. (see [below for nested schema](#nestedatt--alert_config--receivers--webhooks_configs))
<a id="nestedatt--alert_config--receivers--email_configs"></a>
### Nested Schema for `alert_config.receivers.email_configs`
Read-Only:
- `auth_identity` (String) SMTP authentication information. Must be a valid email address
- `auth_password` (String) SMTP authentication password.
- `auth_username` (String) SMTP authentication username.
- `from` (String) The sender email address. Must be a valid email address
- `smart_host` (String) The SMTP host through which emails are sent.
- `to` (String) The email address to send notifications to. Must be a valid email address
<a id="nestedatt--alert_config--receivers--opsgenie_configs"></a>
### Nested Schema for `alert_config.receivers.opsgenie_configs`
Read-Only:
- `api_key` (String) The API key for OpsGenie.
- `api_url` (String) The host to send OpsGenie API requests to. Must be a valid URL
- `tags` (String) Comma separated list of tags attached to the notifications.
<a id="nestedatt--alert_config--receivers--webhooks_configs"></a>
### Nested Schema for `alert_config.receivers.webhooks_configs`
Read-Only:
- `ms_teams` (Boolean) Microsoft Teams webhooks require special handling, set this to true if the webhook is for Microsoft Teams.
- `url` (String) The endpoint to send HTTP POST requests to. Must be a valid URL
<a id="nestedatt--alert_config--route"></a>
### Nested Schema for `alert_config.route`
Read-Only:
- `group_by` (List of String) The labels by which incoming alerts are grouped together. For example, multiple alerts coming in for cluster=A and alertname=LatencyHigh would be batched into a single group. To aggregate by all possible labels use the special value '...' as the sole label name, for example: group_by: ['...']. This effectively disables aggregation entirely, passing through all alerts as-is. This is unlikely to be what you want, unless you have a very low alert volume or your upstream notification system performs its own grouping.
- `group_interval` (String) How long to wait before sending a notification about new alerts that are added to a group of alerts for which an initial notification has already been sent. (Usually ~5m or more.)
- `group_wait` (String) How long to initially wait to send a notification for a group of alerts. Allows to wait for an inhibiting alert to arrive or collect more initial alerts for the same group. (Usually ~0s to few minutes.) .
- `match` (Map of String) A set of equality matchers an alert has to fulfill to match the node.
- `match_regex` (Map of String) A set of regex-matchers an alert has to fulfill to match the node.
- `receiver` (String) The name of the receiver to route the alerts to.
- `repeat_interval` (String) How long to wait before sending a notification again if it has already been sent successfully for an alert. (Usually ~3h or more).
- `routes` (Attributes List) List of child routes. (see [below for nested schema](#nestedatt--alert_config--route--routes))
<a id="nestedatt--alert_config--route--routes"></a>
### Nested Schema for `alert_config.route.routes`
Read-Only:
- `group_by` (List of String) The labels by which incoming alerts are grouped together. For example, multiple alerts coming in for cluster=A and alertname=LatencyHigh would be batched into a single group. To aggregate by all possible labels use the special value '...' as the sole label name, for example: group_by: ['...']. This effectively disables aggregation entirely, passing through all alerts as-is. This is unlikely to be what you want, unless you have a very low alert volume or your upstream notification system performs its own grouping.
- `group_interval` (String) How long to wait before sending a notification about new alerts that are added to a group of alerts for which an initial notification has already been sent. (Usually ~5m or more.)
- `group_wait` (String) How long to initially wait to send a notification for a group of alerts. Allows to wait for an inhibiting alert to arrive or collect more initial alerts for the same group. (Usually ~0s to few minutes.)
- `match` (Map of String) A set of equality matchers an alert has to fulfill to match the node.
- `match_regex` (Map of String) A set of regex-matchers an alert has to fulfill to match the node.
- `receiver` (String) The name of the receiver to route the alerts to.
- `repeat_interval` (String) How long to wait before sending a notification again if it has already been sent successfully for an alert. (Usually ~3h or more).

View file

@ -1,70 +0,0 @@
---
# generated by https://github.com/hashicorp/terraform-plugin-docs
page_title: "stackit_argus_scrapeconfig Data Source - stackit"
subcategory: ""
description: |-
Argus scrape config data source schema. Must have a region specified in the provider configuration.
!> The stackit_argus_scrapeconfig data source has been deprecated and will be removed after February 26th 2025. Please use stackit_observability_scrapeconfig instead, which offers the exact same functionality.
---
# stackit_argus_scrapeconfig (Data Source)
Argus scrape config data source schema. Must have a `region` specified in the provider configuration.
!> The `stackit_argus_scrapeconfig` data source has been deprecated and will be removed after February 26th 2025. Please use `stackit_observability_scrapeconfig` instead, which offers the exact same functionality.
## Example Usage
```terraform
data "stackit_argus_scrapeconfig" "example" {
project_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
instance_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
job_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
}
```
<!-- schema generated by tfplugindocs -->
## Schema
### Required
- `instance_id` (String) Argus instance ID to which the scraping job is associated.
- `name` (String) Specifies the name of the scraping job
- `project_id` (String) STACKIT project ID to which the scraping job is associated.
### Read-Only
- `basic_auth` (Attributes) A basic authentication block. (see [below for nested schema](#nestedatt--basic_auth))
- `id` (String) Terraform's internal data source. ID. It is structured as "`project_id`,`instance_id`,`name`".
- `metrics_path` (String) Specifies the job scraping url path.
- `saml2` (Attributes) A SAML2 configuration block. (see [below for nested schema](#nestedatt--saml2))
- `sample_limit` (Number) Specifies the scrape sample limit.
- `scheme` (String) Specifies the http scheme.
- `scrape_interval` (String) Specifies the scrape interval as duration string.
- `scrape_timeout` (String) Specifies the scrape timeout as duration string.
- `targets` (Attributes List) The targets list (specified by the static config). (see [below for nested schema](#nestedatt--targets))
<a id="nestedatt--basic_auth"></a>
### Nested Schema for `basic_auth`
Read-Only:
- `password` (String, Sensitive) Specifies basic auth password.
- `username` (String) Specifies basic auth username.
<a id="nestedatt--saml2"></a>
### Nested Schema for `saml2`
Read-Only:
- `enable_url_parameters` (Boolean) Specifies if URL parameters are enabled
<a id="nestedatt--targets"></a>
### Nested Schema for `targets`
Read-Only:
- `labels` (Map of String) Specifies labels.
- `urls` (List of String) Specifies target URLs.

View file

@ -1,77 +0,0 @@
---
# generated by https://github.com/hashicorp/terraform-plugin-docs
page_title: "stackit_argus_credential Resource - stackit"
subcategory: ""
description: |-
Argus credential resource schema. Must have a region specified in the provider configuration.
!> The stackit_argus_credential resource has been deprecated and will be removed after February 26th 2025. Please use stackit_observability_credential instead, which offers the exact same functionality.
Example move
Example to move the deprecated stackit_argus_credential resource to the new stackit_observability_credential resource:
Add a new stackit_observability_credential resource with the same values like your previous stackit_argus_credential resource.Add a moved block which reference the stackit_argus_credential and stackit_observability_credential resource.Remove your old stackit_argus_credential resource and run $ terraform apply.
resource "stackit_argus_credential" "example" {
project_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
instance_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
}
moved {
from = stackit_argus_credential.example
to = stackit_observability_credential.example
}
resource "stackit_observability_credential" "example" {
project_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
instance_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
}
---
# stackit_argus_credential (Resource)
Argus credential resource schema. Must have a `region` specified in the provider configuration.
!> The `stackit_argus_credential` resource has been deprecated and will be removed after February 26th 2025. Please use `stackit_observability_credential` instead, which offers the exact same functionality.
## Example move
Example to move the deprecated `stackit_argus_credential` resource to the new `stackit_observability_credential` resource:
1. Add a new `stackit_observability_credential` resource with the same values like your previous `stackit_argus_credential` resource.
1. Add a moved block which reference the `stackit_argus_credential` and `stackit_observability_credential` resource.
1. Remove your old `stackit_argus_credential` resource and run `$ terraform apply`.
```terraform
resource "stackit_argus_credential" "example" {
project_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
instance_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
}
moved {
from = stackit_argus_credential.example
to = stackit_observability_credential.example
}
resource "stackit_observability_credential" "example" {
project_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
instance_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
}
```
## Example Usage
```terraform
resource "stackit_argus_credential" "example" {
project_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
instance_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
}
```
<!-- schema generated by tfplugindocs -->
## Schema
### Required
- `instance_id` (String) The Argus Instance ID the credential belongs to.
- `project_id` (String) STACKIT project ID to which the credential is associated.
### Read-Only
- `id` (String) Terraform's internal resource ID. It is structured as "`project_id`,`instance_id`,`username`".
- `password` (String, Sensitive) Credential password
- `username` (String) Credential username

View file

@ -1,235 +0,0 @@
---
# generated by https://github.com/hashicorp/terraform-plugin-docs
page_title: "stackit_argus_instance Resource - stackit"
subcategory: ""
description: |-
Argus instance resource schema. Must have a region specified in the provider configuration.
!> The stackit_argus_instance resource has been deprecated and will be removed after February 26th 2025. Please use stackit_observability_instance instead, which offers the exact same functionality.
Example move
Example to move the deprecated stackit_argus_instance resource to the newstackit_observability_instance resource:
Add a new stackit_observability_instance resource with the same values like your previous stackit_argus_instance resource.Add a moved block which reference the stackit_argus_instance and stackit_observability_instance resource.Remove your old stackit_argus_instance resource and run $ terraform apply.
resource "stackit_argus_instance" "example" {
project_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
name = "example-instance"
plan_name = "Monitoring-Medium-EU01"
acl = ["1.1.1.1/32", "2.2.2.2/32"]
metrics_retention_days = 7
metrics_retention_days_5m_downsampling = 30
metrics_retention_days_1h_downsampling = 365
}
moved {
from = stackit_argus_instance.example
to = stackit_observability_instance.example
}
resource "stackit_observability_instance" "example" {
project_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
name = "example-instance"
plan_name = "Monitoring-Medium-EU01"
acl = ["1.1.1.1/32", "2.2.2.2/32"]
metrics_retention_days = 7
metrics_retention_days_5m_downsampling = 30
metrics_retention_days_1h_downsampling = 365
}
---
# stackit_argus_instance (Resource)
Argus instance resource schema. Must have a `region` specified in the provider configuration.
!> The `stackit_argus_instance` resource has been deprecated and will be removed after February 26th 2025. Please use `stackit_observability_instance` instead, which offers the exact same functionality.
## Example move
Example to move the deprecated `stackit_argus_instance` resource to the new`stackit_observability_instance` resource:
1. Add a new `stackit_observability_instance` resource with the same values like your previous `stackit_argus_instance` resource.
1. Add a moved block which reference the `stackit_argus_instance` and `stackit_observability_instance` resource.
1. Remove your old `stackit_argus_instance` resource and run `$ terraform apply`.
```terraform
resource "stackit_argus_instance" "example" {
project_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
name = "example-instance"
plan_name = "Monitoring-Medium-EU01"
acl = ["1.1.1.1/32", "2.2.2.2/32"]
metrics_retention_days = 7
metrics_retention_days_5m_downsampling = 30
metrics_retention_days_1h_downsampling = 365
}
moved {
from = stackit_argus_instance.example
to = stackit_observability_instance.example
}
resource "stackit_observability_instance" "example" {
project_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
name = "example-instance"
plan_name = "Monitoring-Medium-EU01"
acl = ["1.1.1.1/32", "2.2.2.2/32"]
metrics_retention_days = 7
metrics_retention_days_5m_downsampling = 30
metrics_retention_days_1h_downsampling = 365
}
```
## Example Usage
```terraform
resource "stackit_argus_instance" "example" {
project_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
name = "example-instance"
plan_name = "Monitoring-Medium-EU01"
acl = ["1.1.1.1/32", "2.2.2.2/32"]
metrics_retention_days = 7
metrics_retention_days_5m_downsampling = 30
metrics_retention_days_1h_downsampling = 365
}
```
<!-- schema generated by tfplugindocs -->
## Schema
### Required
- `name` (String) The name of the Argus instance.
- `plan_name` (String) Specifies the Argus plan. E.g. `Monitoring-Medium-EU01`.
- `project_id` (String) STACKIT project ID to which the instance is associated.
### Optional
- `acl` (Set of String) The access control list for this instance. Each entry is an IP address range that is permitted to access, in CIDR notation.
- `alert_config` (Attributes) Alert configuration for the instance. (see [below for nested schema](#nestedatt--alert_config))
- `metrics_retention_days` (Number) Specifies for how many days the raw metrics are kept.
- `metrics_retention_days_1h_downsampling` (Number) Specifies for how many days the 1h downsampled metrics are kept. must be less than the value of the 5m downsampling retention. Default is set to `0` (disabled).
- `metrics_retention_days_5m_downsampling` (Number) Specifies for how many days the 5m downsampled metrics are kept. must be less than the value of the general retention. Default is set to `0` (disabled).
- `parameters` (Map of String) Additional parameters.
### Read-Only
- `alerting_url` (String) Specifies Alerting URL.
- `dashboard_url` (String) Specifies Argus instance dashboard URL.
- `grafana_initial_admin_password` (String, Sensitive) Specifies an initial Grafana admin password.
- `grafana_initial_admin_user` (String) Specifies an initial Grafana admin username.
- `grafana_public_read_access` (Boolean) If true, anyone can access Grafana dashboards without logging in.
- `grafana_url` (String) Specifies Grafana URL.
- `id` (String) Terraform's internal resource ID. It is structured as "`project_id`,`instance_id`".
- `instance_id` (String) The Argus instance ID.
- `is_updatable` (Boolean) Specifies if the instance can be updated.
- `jaeger_traces_url` (String)
- `jaeger_ui_url` (String)
- `logs_push_url` (String) Specifies URL for pushing logs.
- `logs_url` (String) Specifies Logs URL.
- `metrics_push_url` (String) Specifies URL for pushing metrics.
- `metrics_url` (String) Specifies metrics URL.
- `otlp_traces_url` (String)
- `plan_id` (String) The Argus plan ID.
- `targets_url` (String) Specifies Targets URL.
- `zipkin_spans_url` (String)
<a id="nestedatt--alert_config"></a>
### Nested Schema for `alert_config`
Required:
- `receivers` (Attributes List) List of alert receivers. (see [below for nested schema](#nestedatt--alert_config--receivers))
- `route` (Attributes) Route configuration for the alerts. (see [below for nested schema](#nestedatt--alert_config--route))
Optional:
- `global` (Attributes) Global configuration for the alerts. (see [below for nested schema](#nestedatt--alert_config--global))
<a id="nestedatt--alert_config--receivers"></a>
### Nested Schema for `alert_config.receivers`
Required:
- `name` (String) Name of the receiver.
Optional:
- `email_configs` (Attributes List) List of email configurations. (see [below for nested schema](#nestedatt--alert_config--receivers--email_configs))
- `opsgenie_configs` (Attributes List) List of OpsGenie configurations. (see [below for nested schema](#nestedatt--alert_config--receivers--opsgenie_configs))
- `webhooks_configs` (Attributes List) List of Webhooks configurations. (see [below for nested schema](#nestedatt--alert_config--receivers--webhooks_configs))
<a id="nestedatt--alert_config--receivers--email_configs"></a>
### Nested Schema for `alert_config.receivers.email_configs`
Optional:
- `auth_identity` (String) SMTP authentication information. Must be a valid email address
- `auth_password` (String) SMTP authentication password.
- `auth_username` (String) SMTP authentication username.
- `from` (String) The sender email address. Must be a valid email address
- `smart_host` (String) The SMTP host through which emails are sent.
- `to` (String) The email address to send notifications to. Must be a valid email address
<a id="nestedatt--alert_config--receivers--opsgenie_configs"></a>
### Nested Schema for `alert_config.receivers.opsgenie_configs`
Optional:
- `api_key` (String) The API key for OpsGenie.
- `api_url` (String) The host to send OpsGenie API requests to. Must be a valid URL
- `tags` (String) Comma separated list of tags attached to the notifications.
<a id="nestedatt--alert_config--receivers--webhooks_configs"></a>
### Nested Schema for `alert_config.receivers.webhooks_configs`
Optional:
- `ms_teams` (Boolean) Microsoft Teams webhooks require special handling, set this to true if the webhook is for Microsoft Teams.
- `url` (String) The endpoint to send HTTP POST requests to. Must be a valid URL
<a id="nestedatt--alert_config--route"></a>
### Nested Schema for `alert_config.route`
Required:
- `receiver` (String) The name of the receiver to route the alerts to.
Optional:
- `group_by` (List of String) The labels by which incoming alerts are grouped together. For example, multiple alerts coming in for cluster=A and alertname=LatencyHigh would be batched into a single group. To aggregate by all possible labels use the special value '...' as the sole label name, for example: group_by: ['...']. This effectively disables aggregation entirely, passing through all alerts as-is. This is unlikely to be what you want, unless you have a very low alert volume or your upstream notification system performs its own grouping.
- `group_interval` (String) How long to wait before sending a notification about new alerts that are added to a group of alerts for which an initial notification has already been sent. (Usually ~5m or more.)
- `group_wait` (String) How long to initially wait to send a notification for a group of alerts. Allows to wait for an inhibiting alert to arrive or collect more initial alerts for the same group. (Usually ~0s to few minutes.)
- `match` (Map of String) A set of equality matchers an alert has to fulfill to match the node.
- `match_regex` (Map of String) A set of regex-matchers an alert has to fulfill to match the node.
- `repeat_interval` (String) How long to wait before sending a notification again if it has already been sent successfully for an alert. (Usually ~3h or more).
- `routes` (Attributes List) List of child routes. (see [below for nested schema](#nestedatt--alert_config--route--routes))
<a id="nestedatt--alert_config--route--routes"></a>
### Nested Schema for `alert_config.route.routes`
Required:
- `receiver` (String) The name of the receiver to route the alerts to.
Optional:
- `group_by` (List of String) The labels by which incoming alerts are grouped together. For example, multiple alerts coming in for cluster=A and alertname=LatencyHigh would be batched into a single group. To aggregate by all possible labels use the special value '...' as the sole label name, for example: group_by: ['...']. This effectively disables aggregation entirely, passing through all alerts as-is. This is unlikely to be what you want, unless you have a very low alert volume or your upstream notification system performs its own grouping.
- `group_interval` (String) How long to wait before sending a notification about new alerts that are added to a group of alerts for which an initial notification has already been sent. (Usually ~5m or more.)
- `group_wait` (String) How long to initially wait to send a notification for a group of alerts. Allows to wait for an inhibiting alert to arrive or collect more initial alerts for the same group. (Usually ~0s to few minutes.)
- `match` (Map of String) A set of equality matchers an alert has to fulfill to match the node.
- `match_regex` (Map of String) A set of regex-matchers an alert has to fulfill to match the node.
- `repeat_interval` (String) How long to wait before sending a notification again if it has already been sent successfully for an alert. (Usually ~3h or more).
<a id="nestedatt--alert_config--global"></a>
### Nested Schema for `alert_config.global`
Optional:
- `opsgenie_api_key` (String, Sensitive) The API key for OpsGenie.
- `opsgenie_api_url` (String) The host to send OpsGenie API requests to. Must be a valid URL
- `resolve_timeout` (String) The default value used by alertmanager if the alert does not include EndsAt. After this time passes, it can declare the alert as resolved if it has not been updated. This has no impact on alerts from Prometheus, as they always include EndsAt.
- `smtp_auth_identity` (String) SMTP authentication information. Must be a valid email address
- `smtp_auth_password` (String, Sensitive) SMTP Auth using LOGIN and PLAIN.
- `smtp_auth_username` (String) SMTP Auth using CRAM-MD5, LOGIN and PLAIN. If empty, Alertmanager doesn't authenticate to the SMTP server.
- `smtp_from` (String) The default SMTP From header field. Must be a valid email address
- `smtp_smart_host` (String) The default SMTP smarthost used for sending emails, including port number in format `host:port` (eg. `smtp.example.com:587`). Port number usually is 25, or 587 for SMTP over TLS (sometimes referred to as STARTTLS).

View file

@ -1,180 +0,0 @@
---
# generated by https://github.com/hashicorp/terraform-plugin-docs
page_title: "stackit_argus_scrapeconfig Resource - stackit"
subcategory: ""
description: |-
Argus scrape config resource schema. Must have a region specified in the provider configuration.
!> The stackit_argus_scrapeconfig resource has been deprecated and will be removed after February 26th 2025. Please use stackit_observability_scrapeconfig instead, which offers the exact same functionality.
Example move
Example to move the deprecated stackit_argus_scrapeconfig resource to the new stackit_observability_scrapeconfig resource:
Add a new stackit_observability_scrapeconfig resource with the same values like your previous stackit_argus_scrapeconfig resource.Add a moved block which reference the stackit_argus_scrapeconfig and stackit_observability_scrapeconfig resource.Remove your old stackit_argus_scrapeconfig resource and run $ terraform apply.
resource "stackit_argus_scrapeconfig" "example" {
project_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
instance_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
name = "example-job"
metrics_path = "/my-metrics"
saml2 = {
enable_url_parameters = true
}
targets = [
{
urls = ["url1", "urls2"]
labels = {
"url1" = "dev"
}
}
]
}
moved {
from = stackit_argus_scrapeconfig.example
to = stackit_observability_scrapeconfig.example
}
resource "stackit_observability_scrapeconfig" "example" {
project_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
instance_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
name = "example-job"
metrics_path = "/my-metrics"
saml2 = {
enable_url_parameters = true
}
targets = [
{
urls = ["url1", "urls2"]
labels = {
"url1" = "dev"
}
}
]
}
---
# stackit_argus_scrapeconfig (Resource)
Argus scrape config resource schema. Must have a `region` specified in the provider configuration.
!> The `stackit_argus_scrapeconfig` resource has been deprecated and will be removed after February 26th 2025. Please use `stackit_observability_scrapeconfig` instead, which offers the exact same functionality.
## Example move
Example to move the deprecated `stackit_argus_scrapeconfig` resource to the new `stackit_observability_scrapeconfig` resource:
1. Add a new `stackit_observability_scrapeconfig` resource with the same values like your previous `stackit_argus_scrapeconfig` resource.
1. Add a moved block which reference the `stackit_argus_scrapeconfig` and `stackit_observability_scrapeconfig` resource.
1. Remove your old `stackit_argus_scrapeconfig` resource and run `$ terraform apply`.
```terraform
resource "stackit_argus_scrapeconfig" "example" {
project_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
instance_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
name = "example-job"
metrics_path = "/my-metrics"
saml2 = {
enable_url_parameters = true
}
targets = [
{
urls = ["url1", "urls2"]
labels = {
"url1" = "dev"
}
}
]
}
moved {
from = stackit_argus_scrapeconfig.example
to = stackit_observability_scrapeconfig.example
}
resource "stackit_observability_scrapeconfig" "example" {
project_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
instance_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
name = "example-job"
metrics_path = "/my-metrics"
saml2 = {
enable_url_parameters = true
}
targets = [
{
urls = ["url1", "urls2"]
labels = {
"url1" = "dev"
}
}
]
}
```
## Example Usage
```terraform
resource "stackit_argus_scrapeconfig" "example" {
project_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
instance_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
name = "example-job"
metrics_path = "/my-metrics"
saml2 = {
enable_url_parameters = true
}
targets = [
{
urls = ["url1", "urls2"]
labels = {
"url1" = "dev"
}
}
]
}
```
<!-- schema generated by tfplugindocs -->
## Schema
### Required
- `instance_id` (String) Argus instance ID to which the scraping job is associated.
- `metrics_path` (String) Specifies the job scraping url path. E.g. `/metrics`.
- `name` (String) Specifies the name of the scraping job.
- `project_id` (String) STACKIT project ID to which the scraping job is associated.
- `targets` (Attributes List) The targets list (specified by the static config). (see [below for nested schema](#nestedatt--targets))
### Optional
- `basic_auth` (Attributes) A basic authentication block. (see [below for nested schema](#nestedatt--basic_auth))
- `saml2` (Attributes) A SAML2 configuration block. (see [below for nested schema](#nestedatt--saml2))
- `sample_limit` (Number) Specifies the scrape sample limit. Upper limit depends on the service plan. Defaults to `5000`.
- `scheme` (String) Specifies the http scheme. Defaults to `https`.
- `scrape_interval` (String) Specifies the scrape interval as duration string. Defaults to `5m`.
- `scrape_timeout` (String) Specifies the scrape timeout as duration string. Defaults to `2m`.
### Read-Only
- `id` (String) Terraform's internal resource ID. It is structured as "`project_id`,`instance_id`,`name`".
<a id="nestedatt--targets"></a>
### Nested Schema for `targets`
Required:
- `urls` (List of String) Specifies target URLs.
Optional:
- `labels` (Map of String) Specifies labels.
<a id="nestedatt--basic_auth"></a>
### Nested Schema for `basic_auth`
Required:
- `password` (String, Sensitive) Specifies basic auth password.
- `username` (String) Specifies basic auth username.
<a id="nestedatt--saml2"></a>
### Nested Schema for `saml2`
Optional:
- `enable_url_parameters` (Boolean) Specifies if URL parameters are enabled. Defaults to `true`

View file

@ -1,4 +0,0 @@
data "stackit_argus_instance" "example" {
project_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
instance_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
}

View file

@ -1,5 +0,0 @@
data "stackit_argus_scrapeconfig" "example" {
project_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
instance_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
job_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
}

View file

@ -1,5 +1,5 @@
data "stackit_observability_scrapeconfig" "example" { data "stackit_observability_scrapeconfig" "example" {
project_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" project_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
instance_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" instance_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
job_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" name = "example"
} }

View file

@ -1,4 +0,0 @@
resource "stackit_argus_credential" "example" {
project_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
instance_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
}

View file

@ -1,9 +0,0 @@
resource "stackit_argus_instance" "example" {
project_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
name = "example-instance"
plan_name = "Monitoring-Medium-EU01"
acl = ["1.1.1.1/32", "2.2.2.2/32"]
metrics_retention_days = 7
metrics_retention_days_5m_downsampling = 30
metrics_retention_days_1h_downsampling = 365
}

View file

@ -1,17 +0,0 @@
resource "stackit_argus_scrapeconfig" "example" {
project_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
instance_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
name = "example-job"
metrics_path = "/my-metrics"
saml2 = {
enable_url_parameters = true
}
targets = [
{
urls = ["url1", "urls2"]
labels = {
"url1" = "dev"
}
}
]
}

View file

@ -1,896 +0,0 @@
package argus_test
import (
"context"
"fmt"
"strings"
"testing"
"github.com/hashicorp/terraform-plugin-testing/helper/acctest"
"github.com/hashicorp/terraform-plugin-testing/helper/resource"
"github.com/hashicorp/terraform-plugin-testing/terraform"
"github.com/stackitcloud/stackit-sdk-go/core/config"
"github.com/stackitcloud/stackit-sdk-go/core/utils"
"github.com/stackitcloud/stackit-sdk-go/services/argus"
"github.com/stackitcloud/stackit-sdk-go/services/argus/wait"
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/core"
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/testutil"
)
var instanceResource = map[string]string{
"project_id": testutil.ProjectId,
"name": testutil.ResourceNameWithDateTime("argus"),
"plan_name": "Observability-Monitoring-Basic-EU01",
"new_plan_name": "Observability-Monitoring-Medium-EU01",
"acl-0": "1.2.3.4/32",
"acl-1": "111.222.111.222/32",
"acl-1-updated": "111.222.111.125/32",
"metrics_retention_days": "60",
"metrics_retention_days_5m_downsampling": "30",
"metrics_retention_days_1h_downsampling": "15",
}
var scrapeConfigResource = map[string]string{
"project_id": testutil.ProjectId,
"name": fmt.Sprintf("scrapeconfig-%s", acctest.RandStringFromCharSet(7, acctest.CharSetAlphaNum)),
"urls": fmt.Sprintf(`{urls = ["www.%s.de","%s.de"]}`, acctest.RandStringFromCharSet(15, acctest.CharSetAlphaNum), acctest.RandStringFromCharSet(15, acctest.CharSetAlphaNum)),
"metrics_path": "/metrics",
"scheme": "https",
"scrape_interval": "4m", // non-default
"sample_limit": "7", // non-default
"saml2_enable_url_parameters": "false",
}
var credentialResource = map[string]string{
"project_id": testutil.ProjectId,
}
func buildAlertConfigReceivers(hasOpsGenie, hasEmail, hasWebhook bool) string {
if !hasOpsGenie && !hasEmail && !hasWebhook {
return ""
}
receivers := "["
if hasOpsGenie {
receivers += `
{
name = "OpsGenieReceiverInfo"
opsgenie_configs = [
{
tags = "iam,argus-alert"
api_key = "example-api-key"
}
]
},
`
}
if hasEmail {
receivers += `
{
name = "EmailReceiverInfo"
email_configs = [
{
to = "me@example.com"
},
]
},
`
}
if hasWebhook {
receivers += `
{
name = "WebhookReceiverInfo"
webhooks_configs = [
{
url = "https://example.com"
ms_teams = true
},
]
},
`
}
return receivers + "]"
}
func buildAlertConfigRoute(childRoutes bool) string {
route := `{
receiver = "OpsGenieReceiverInfo"
group_by = ["alertname"]
group_interval = "10m"
group_wait = "1m"
repeat_interval = "1h"`
if childRoutes {
route += `
routes = [
{
match = {
severity = "critical"
}
receiver = "OpsGenieReceiverInfo"
},
{
match = {
severity = "warning"
}
receiver = "WebhookReceiverInfo"
}
]`
}
return route + "\n}"
}
func buildAlertConfigGlobal(includeEmailOptions bool) string {
defaultOptions := `{
resolve_timeout = "5m"
opsgenie_api_key = "example-api-key"
opsgenie_api_url = "https://api.eu.opsgenie.com"`
if !includeEmailOptions {
return defaultOptions + "\n}"
}
return defaultOptions + `
smtp_smart_host = "smtp.example.com:587"
smtp_from = "me@example.com"
}`
}
func buildAlertConfig(receivers, route, global string) *string {
if receivers == "" && route == "" && global == "" {
return nil
}
returnStr := fmt.Sprintf(`
alert_config = {
receivers = %s,
route = %s,
global = %s
}
`, receivers, route, global)
return &returnStr
}
func instanceResourceConfig(acl, metricsRetentionDays, metricsRetentionDays1hDownsampling, metricsRetentionDays5mDownsampling, alertConfig *string, instanceName, planName string) string {
var aclStr string
var metricsRetentionDaysStr string
var metricsRetentionDays1hDownsamplingStr string
var metricsRetentionDays5mDownsamplingStr string
var alertConfigStr string
if acl != nil {
aclStr = fmt.Sprintf("acl = %s", *acl)
}
if metricsRetentionDays != nil {
metricsRetentionDaysStr = fmt.Sprintf("metrics_retention_days = %s", *metricsRetentionDays)
}
if metricsRetentionDays1hDownsampling != nil {
metricsRetentionDays1hDownsamplingStr = fmt.Sprintf("metrics_retention_days_1h_downsampling = %s", *metricsRetentionDays1hDownsampling)
}
if metricsRetentionDays5mDownsampling != nil {
metricsRetentionDays5mDownsamplingStr = fmt.Sprintf("metrics_retention_days_5m_downsampling = %s", *metricsRetentionDays5mDownsampling)
}
if alertConfig != nil {
alertConfigStr = *alertConfig
}
optionalsStr := strings.Join([]string{aclStr, metricsRetentionDaysStr, metricsRetentionDays1hDownsamplingStr, metricsRetentionDays5mDownsamplingStr, alertConfigStr}, "\n")
return fmt.Sprintf(`
resource "stackit_argus_instance" "instance" {
project_id = "%s"
name = "%s"
plan_name = "%s"
%s
}
`,
instanceResource["project_id"],
instanceName,
planName,
optionalsStr,
)
}
func scrapeConfigResourceConfig(target, saml2EnableUrlParameters string) string {
return fmt.Sprintf(
`resource "stackit_argus_scrapeconfig" "scrapeconfig" {
project_id = stackit_argus_instance.instance.project_id
instance_id = stackit_argus_instance.instance.instance_id
name = "%s"
metrics_path = "%s"
targets = [%s]
scrape_interval = "%s"
sample_limit = %s
saml2 = {
enable_url_parameters = %s
}
}`,
scrapeConfigResource["name"],
scrapeConfigResource["metrics_path"],
target,
scrapeConfigResource["scrape_interval"],
scrapeConfigResource["sample_limit"],
saml2EnableUrlParameters,
)
}
func credentialResourceConfig() string {
return `resource "stackit_argus_credential" "credential" {
project_id = stackit_argus_instance.instance.project_id
instance_id = stackit_argus_instance.instance.instance_id
}`
}
func resourceConfig(acl, metricsRetentionDays, metricsRetentionDays1hDownsampling, metricsRetentionDays5mDownsampling, alertConfig *string, instanceName, planName, target, saml2EnableUrlParameters string) string {
return fmt.Sprintf("%s\n\n%s\n\n%s\n\n%s",
testutil.ArgusProviderConfig(),
instanceResourceConfig(acl,
metricsRetentionDays,
metricsRetentionDays1hDownsampling,
metricsRetentionDays5mDownsampling,
alertConfig,
instanceName,
planName),
scrapeConfigResourceConfig(target, saml2EnableUrlParameters),
credentialResourceConfig(),
)
}
func TestAccResource(t *testing.T) {
resource.Test(t, resource.TestCase{
ProtoV6ProviderFactories: testutil.TestAccProtoV6ProviderFactories,
CheckDestroy: testAccCheckArgusDestroy,
Steps: []resource.TestStep{
// Creation
{
Config: resourceConfig(
utils.Ptr(fmt.Sprintf(
"[%q, %q, %q]",
instanceResource["acl-0"],
instanceResource["acl-1"],
instanceResource["acl-1"],
)),
utils.Ptr(instanceResource["metrics_retention_days"]),
utils.Ptr(instanceResource["metrics_retention_days_1h_downsampling"]),
utils.Ptr(instanceResource["metrics_retention_days_5m_downsampling"]),
buildAlertConfig(buildAlertConfigReceivers(true, false, true), buildAlertConfigRoute(false), buildAlertConfigGlobal(false)),
instanceResource["name"],
instanceResource["plan_name"],
scrapeConfigResource["urls"],
scrapeConfigResource["saml2_enable_url_parameters"],
),
Check: resource.ComposeAggregateTestCheckFunc(
// Instance data
resource.TestCheckResourceAttr("stackit_argus_instance.instance", "project_id", instanceResource["project_id"]),
resource.TestCheckResourceAttrSet("stackit_argus_instance.instance", "instance_id"),
resource.TestCheckResourceAttr("stackit_argus_instance.instance", "name", instanceResource["name"]),
resource.TestCheckResourceAttr("stackit_argus_instance.instance", "plan_name", instanceResource["plan_name"]),
resource.TestCheckResourceAttrSet("stackit_argus_instance.instance", "dashboard_url"),
resource.TestCheckResourceAttrSet("stackit_argus_instance.instance", "is_updatable"),
resource.TestCheckResourceAttrSet("stackit_argus_instance.instance", "grafana_public_read_access"),
resource.TestCheckResourceAttrSet("stackit_argus_instance.instance", "grafana_url"),
resource.TestCheckResourceAttrSet("stackit_argus_instance.instance", "grafana_initial_admin_user"),
resource.TestCheckResourceAttrSet("stackit_argus_instance.instance", "grafana_initial_admin_password"),
resource.TestCheckResourceAttr("stackit_argus_instance.instance", "metrics_retention_days", instanceResource["metrics_retention_days"]),
resource.TestCheckResourceAttr("stackit_argus_instance.instance", "metrics_retention_days_5m_downsampling", instanceResource["metrics_retention_days_5m_downsampling"]),
resource.TestCheckResourceAttr("stackit_argus_instance.instance", "metrics_retention_days_1h_downsampling", instanceResource["metrics_retention_days_1h_downsampling"]),
resource.TestCheckResourceAttrSet("stackit_argus_instance.instance", "metrics_url"),
resource.TestCheckResourceAttrSet("stackit_argus_instance.instance", "metrics_push_url"),
resource.TestCheckResourceAttrSet("stackit_argus_instance.instance", "targets_url"),
resource.TestCheckResourceAttrSet("stackit_argus_instance.instance", "alerting_url"),
resource.TestCheckResourceAttrSet("stackit_argus_instance.instance", "logs_url"),
resource.TestCheckResourceAttrSet("stackit_argus_instance.instance", "logs_push_url"),
resource.TestCheckResourceAttrSet("stackit_argus_instance.instance", "jaeger_traces_url"),
resource.TestCheckResourceAttrSet("stackit_argus_instance.instance", "jaeger_ui_url"),
resource.TestCheckResourceAttrSet("stackit_argus_instance.instance", "otlp_traces_url"),
resource.TestCheckResourceAttrSet("stackit_argus_instance.instance", "zipkin_spans_url"),
// Alert Config
resource.TestCheckResourceAttr("stackit_argus_instance.instance", "alert_config.receivers.#", "2"),
resource.TestCheckResourceAttr("stackit_argus_instance.instance", "alert_config.route.group_by.#", "1"),
resource.TestCheckResourceAttr("stackit_argus_instance.instance", "alert_config.route.group_by.0", "alertname"),
resource.TestCheckResourceAttr("stackit_argus_instance.instance", "alert_config.route.group_interval", "10m"),
resource.TestCheckResourceAttr("stackit_argus_instance.instance", "alert_config.route.group_wait", "1m"),
resource.TestCheckResourceAttr("stackit_argus_instance.instance", "alert_config.route.repeat_interval", "1h"),
resource.TestCheckResourceAttr("stackit_argus_instance.instance", "alert_config.global.resolve_timeout", "5m"),
resource.TestCheckResourceAttr("stackit_argus_instance.instance", "alert_config.global.opsgenie_api_key", "example-api-key"),
resource.TestCheckResourceAttr("stackit_argus_instance.instance", "alert_config.global.opsgenie_api_url", "https://api.eu.opsgenie.com"),
resource.TestCheckResourceAttr("stackit_argus_instance.instance", "alert_config.route.receiver", "OpsGenieReceiverInfo"),
resource.TestCheckResourceAttr("stackit_argus_instance.instance", "alert_config.route.group_by.#", "1"),
resource.TestCheckResourceAttr("stackit_argus_instance.instance", "alert_config.route.group_by.0", "alertname"),
resource.TestCheckResourceAttr("stackit_argus_instance.instance", "alert_config.route.group_interval", "10m"),
resource.TestCheckResourceAttr("stackit_argus_instance.instance", "alert_config.route.group_wait", "1m"),
resource.TestCheckResourceAttr("stackit_argus_instance.instance", "alert_config.route.repeat_interval", "1h"),
resource.TestCheckResourceAttr("stackit_argus_instance.instance", "alert_config.route.routes.#", "0"),
resource.TestCheckResourceAttr("stackit_argus_instance.instance", "alert_config.receivers.0.name", "OpsGenieReceiverInfo"),
resource.TestCheckResourceAttr("stackit_argus_instance.instance", "alert_config.receivers.0.opsgenie_configs.#", "1"),
resource.TestCheckResourceAttr("stackit_argus_instance.instance", "alert_config.receivers.0.opsgenie_configs.0.tags", "iam,argus-alert"),
resource.TestCheckResourceAttr("stackit_argus_instance.instance", "alert_config.receivers.0.opsgenie_configs.0.api_key",
"example-api-key"),
resource.TestCheckResourceAttr("stackit_argus_instance.instance", "alert_config.receivers.1.name", "WebhookReceiverInfo"),
resource.TestCheckResourceAttr("stackit_argus_instance.instance", "alert_config.receivers.1.webhooks_configs.#", "1"),
resource.TestCheckResourceAttr("stackit_argus_instance.instance", "alert_config.receivers.1.webhooks_configs.0.url", "https://example.com"),
resource.TestCheckResourceAttr("stackit_argus_instance.instance", "alert_config.receivers.1.webhooks_configs.0.ms_teams", "true"),
// ACL
resource.TestCheckResourceAttr("stackit_argus_instance.instance", "acl.#", "2"),
resource.TestCheckResourceAttr("stackit_argus_instance.instance", "acl.0", instanceResource["acl-0"]),
resource.TestCheckResourceAttr("stackit_argus_instance.instance", "acl.1", instanceResource["acl-1"]),
// scrape config data
resource.TestCheckResourceAttrPair(
"stackit_argus_instance.instance", "project_id",
"stackit_argus_scrapeconfig.scrapeconfig", "project_id",
),
resource.TestCheckResourceAttrPair(
"stackit_argus_instance.instance", "instance_id",
"stackit_argus_scrapeconfig.scrapeconfig", "instance_id",
),
resource.TestCheckResourceAttr("stackit_argus_scrapeconfig.scrapeconfig", "name", scrapeConfigResource["name"]),
resource.TestCheckResourceAttr("stackit_argus_scrapeconfig.scrapeconfig", "targets.0.urls.#", "2"),
resource.TestCheckResourceAttr("stackit_argus_scrapeconfig.scrapeconfig", "metrics_path", scrapeConfigResource["metrics_path"]),
resource.TestCheckResourceAttr("stackit_argus_scrapeconfig.scrapeconfig", "scheme", scrapeConfigResource["scheme"]),
resource.TestCheckResourceAttr("stackit_argus_scrapeconfig.scrapeconfig", "scrape_interval", scrapeConfigResource["scrape_interval"]),
resource.TestCheckResourceAttr("stackit_argus_scrapeconfig.scrapeconfig", "sample_limit", scrapeConfigResource["sample_limit"]),
resource.TestCheckResourceAttr("stackit_argus_scrapeconfig.scrapeconfig", "saml2.enable_url_parameters", scrapeConfigResource["saml2_enable_url_parameters"]),
// credentials
resource.TestCheckResourceAttr("stackit_argus_credential.credential", "project_id", credentialResource["project_id"]),
resource.TestCheckResourceAttrPair(
"stackit_argus_instance.instance", "instance_id",
"stackit_argus_credential.credential", "instance_id",
),
resource.TestCheckResourceAttrSet("stackit_argus_credential.credential", "username"),
resource.TestCheckResourceAttrSet("stackit_argus_credential.credential", "password"),
),
},
// Update Alert Config with complete Receiver (email, webhook and opsgenie configs), global options and Route with child routes
{
Config: resourceConfig(
utils.Ptr(fmt.Sprintf(
"[%q, %q, %q]",
instanceResource["acl-0"],
instanceResource["acl-1"],
instanceResource["acl-1"],
)),
utils.Ptr(instanceResource["metrics_retention_days"]),
utils.Ptr(instanceResource["metrics_retention_days_1h_downsampling"]),
utils.Ptr(instanceResource["metrics_retention_days_5m_downsampling"]),
buildAlertConfig(buildAlertConfigReceivers(true, true, true), buildAlertConfigRoute(true), buildAlertConfigGlobal(true)),
instanceResource["name"],
instanceResource["plan_name"],
scrapeConfigResource["urls"],
scrapeConfigResource["saml2_enable_url_parameters"],
),
Check: resource.ComposeAggregateTestCheckFunc(
// Instance data
resource.TestCheckResourceAttr("stackit_argus_instance.instance", "project_id", instanceResource["project_id"]),
resource.TestCheckResourceAttrSet("stackit_argus_instance.instance", "instance_id"),
resource.TestCheckResourceAttr("stackit_argus_instance.instance", "name", instanceResource["name"]),
resource.TestCheckResourceAttr("stackit_argus_instance.instance", "plan_name", instanceResource["plan_name"]),
resource.TestCheckResourceAttrSet("stackit_argus_instance.instance", "dashboard_url"),
resource.TestCheckResourceAttrSet("stackit_argus_instance.instance", "is_updatable"),
resource.TestCheckResourceAttrSet("stackit_argus_instance.instance", "grafana_public_read_access"),
resource.TestCheckResourceAttrSet("stackit_argus_instance.instance", "grafana_url"),
resource.TestCheckResourceAttrSet("stackit_argus_instance.instance", "grafana_initial_admin_user"),
resource.TestCheckResourceAttrSet("stackit_argus_instance.instance", "grafana_initial_admin_password"),
resource.TestCheckResourceAttr("stackit_argus_instance.instance", "metrics_retention_days", instanceResource["metrics_retention_days"]),
resource.TestCheckResourceAttr("stackit_argus_instance.instance", "metrics_retention_days_5m_downsampling", instanceResource["metrics_retention_days_5m_downsampling"]),
resource.TestCheckResourceAttr("stackit_argus_instance.instance", "metrics_retention_days_1h_downsampling", instanceResource["metrics_retention_days_1h_downsampling"]),
resource.TestCheckResourceAttrSet("stackit_argus_instance.instance", "metrics_url"),
resource.TestCheckResourceAttrSet("stackit_argus_instance.instance", "metrics_push_url"),
resource.TestCheckResourceAttrSet("stackit_argus_instance.instance", "targets_url"),
resource.TestCheckResourceAttrSet("stackit_argus_instance.instance", "alerting_url"),
resource.TestCheckResourceAttrSet("stackit_argus_instance.instance", "logs_url"),
resource.TestCheckResourceAttrSet("stackit_argus_instance.instance", "logs_push_url"),
resource.TestCheckResourceAttrSet("stackit_argus_instance.instance", "jaeger_traces_url"),
resource.TestCheckResourceAttrSet("stackit_argus_instance.instance", "jaeger_ui_url"),
resource.TestCheckResourceAttrSet("stackit_argus_instance.instance", "otlp_traces_url"),
resource.TestCheckResourceAttrSet("stackit_argus_instance.instance", "zipkin_spans_url"),
// Alert Config
resource.TestCheckResourceAttr("stackit_argus_instance.instance", "alert_config.receivers.#", "3"),
resource.TestCheckResourceAttr("stackit_argus_instance.instance", "alert_config.route.group_by.#", "1"),
resource.TestCheckResourceAttr("stackit_argus_instance.instance", "alert_config.route.group_by.0", "alertname"),
resource.TestCheckResourceAttr("stackit_argus_instance.instance", "alert_config.route.group_interval", "10m"),
resource.TestCheckResourceAttr("stackit_argus_instance.instance", "alert_config.route.group_wait", "1m"),
resource.TestCheckResourceAttr("stackit_argus_instance.instance", "alert_config.route.repeat_interval", "1h"),
resource.TestCheckResourceAttr("stackit_argus_instance.instance", "alert_config.global.resolve_timeout", "5m"),
resource.TestCheckResourceAttr("stackit_argus_instance.instance", "alert_config.global.opsgenie_api_key", "example-api-key"),
resource.TestCheckResourceAttr("stackit_argus_instance.instance", "alert_config.global.opsgenie_api_url", "https://api.eu.opsgenie.com"),
resource.TestCheckResourceAttr("stackit_argus_instance.instance", "alert_config.global.smtp_smart_host", "smtp.example.com:587"),
resource.TestCheckResourceAttr("stackit_argus_instance.instance", "alert_config.global.smtp_from", "me@example.com"),
resource.TestCheckResourceAttr("stackit_argus_instance.instance", "alert_config.route.receiver", "OpsGenieReceiverInfo"),
resource.TestCheckResourceAttr("stackit_argus_instance.instance", "alert_config.route.group_by.#", "1"),
resource.TestCheckResourceAttr("stackit_argus_instance.instance", "alert_config.route.group_by.0", "alertname"),
resource.TestCheckResourceAttr("stackit_argus_instance.instance", "alert_config.route.group_interval", "10m"),
resource.TestCheckResourceAttr("stackit_argus_instance.instance", "alert_config.route.group_wait", "1m"),
resource.TestCheckResourceAttr("stackit_argus_instance.instance", "alert_config.route.repeat_interval", "1h"),
resource.TestCheckResourceAttr("stackit_argus_instance.instance", "alert_config.route.routes.#", "2"),
resource.TestCheckResourceAttr("stackit_argus_instance.instance", "alert_config.route.routes.0.match.severity", "critical"),
resource.TestCheckResourceAttr("stackit_argus_instance.instance", "alert_config.route.routes.0.receiver", "OpsGenieReceiverInfo"),
resource.TestCheckResourceAttr("stackit_argus_instance.instance", "alert_config.route.routes.1.match.severity", "warning"),
resource.TestCheckResourceAttr("stackit_argus_instance.instance", "alert_config.route.routes.1.receiver", "WebhookReceiverInfo"),
resource.TestCheckResourceAttr("stackit_argus_instance.instance", "alert_config.receivers.0.name", "OpsGenieReceiverInfo"),
resource.TestCheckResourceAttr("stackit_argus_instance.instance", "alert_config.receivers.0.opsgenie_configs.#", "1"),
resource.TestCheckResourceAttr("stackit_argus_instance.instance", "alert_config.receivers.0.opsgenie_configs.0.tags", "iam,argus-alert"),
resource.TestCheckResourceAttr("stackit_argus_instance.instance", "alert_config.receivers.0.opsgenie_configs.0.api_key",
"example-api-key"),
resource.TestCheckResourceAttr("stackit_argus_instance.instance", "alert_config.receivers.1.name", "EmailReceiverInfo"),
resource.TestCheckResourceAttr("stackit_argus_instance.instance", "alert_config.receivers.1.email_configs.#", "1"),
resource.TestCheckResourceAttr("stackit_argus_instance.instance", "alert_config.receivers.1.email_configs.0.to", "me@example.com"),
resource.TestCheckResourceAttr("stackit_argus_instance.instance", "alert_config.receivers.2.name", "WebhookReceiverInfo"),
resource.TestCheckResourceAttr("stackit_argus_instance.instance", "alert_config.receivers.2.webhooks_configs.#", "1"),
resource.TestCheckResourceAttr("stackit_argus_instance.instance", "alert_config.receivers.2.webhooks_configs.0.url", "https://example.com"),
resource.TestCheckResourceAttr("stackit_argus_instance.instance", "alert_config.receivers.2.webhooks_configs.0.ms_teams", "true"),
// ACL
resource.TestCheckResourceAttr("stackit_argus_instance.instance", "acl.#", "2"),
resource.TestCheckResourceAttr("stackit_argus_instance.instance", "acl.0", instanceResource["acl-0"]),
resource.TestCheckResourceAttr("stackit_argus_instance.instance", "acl.1", instanceResource["acl-1"]),
// scrape config data
resource.TestCheckResourceAttrPair(
"stackit_argus_instance.instance", "project_id",
"stackit_argus_scrapeconfig.scrapeconfig", "project_id",
),
resource.TestCheckResourceAttrPair(
"stackit_argus_instance.instance", "instance_id",
"stackit_argus_scrapeconfig.scrapeconfig", "instance_id",
),
resource.TestCheckResourceAttr("stackit_argus_scrapeconfig.scrapeconfig", "name", scrapeConfigResource["name"]),
resource.TestCheckResourceAttr("stackit_argus_scrapeconfig.scrapeconfig", "targets.0.urls.#", "2"),
resource.TestCheckResourceAttr("stackit_argus_scrapeconfig.scrapeconfig", "metrics_path", scrapeConfigResource["metrics_path"]),
resource.TestCheckResourceAttr("stackit_argus_scrapeconfig.scrapeconfig", "scheme", scrapeConfigResource["scheme"]),
resource.TestCheckResourceAttr("stackit_argus_scrapeconfig.scrapeconfig", "scrape_interval", scrapeConfigResource["scrape_interval"]),
resource.TestCheckResourceAttr("stackit_argus_scrapeconfig.scrapeconfig", "sample_limit", scrapeConfigResource["sample_limit"]),
resource.TestCheckResourceAttr("stackit_argus_scrapeconfig.scrapeconfig", "saml2.enable_url_parameters", scrapeConfigResource["saml2_enable_url_parameters"]),
// credentials
resource.TestCheckResourceAttr("stackit_argus_credential.credential", "project_id", credentialResource["project_id"]),
resource.TestCheckResourceAttrPair(
"stackit_argus_instance.instance", "instance_id",
"stackit_argus_credential.credential", "instance_id",
),
resource.TestCheckResourceAttrSet("stackit_argus_credential.credential", "username"),
resource.TestCheckResourceAttrSet("stackit_argus_credential.credential", "password"),
),
},
// Update without ACL, partial metrics retention days and NO alert configs
{
Config: resourceConfig(
nil,
nil,
utils.Ptr(instanceResource["metrics_retention_days_1h_downsampling"]),
nil,
nil,
instanceResource["name"],
instanceResource["plan_name"],
scrapeConfigResource["urls"],
scrapeConfigResource["saml2_enable_url_parameters"],
),
Check: resource.ComposeAggregateTestCheckFunc(
// Instance data
resource.TestCheckResourceAttr("stackit_argus_instance.instance", "project_id", instanceResource["project_id"]),
resource.TestCheckResourceAttrSet("stackit_argus_instance.instance", "instance_id"),
resource.TestCheckResourceAttr("stackit_argus_instance.instance", "name", instanceResource["name"]),
resource.TestCheckResourceAttr("stackit_argus_instance.instance", "plan_name", instanceResource["plan_name"]),
resource.TestCheckResourceAttrSet("stackit_argus_instance.instance", "dashboard_url"),
resource.TestCheckResourceAttrSet("stackit_argus_instance.instance", "is_updatable"),
resource.TestCheckResourceAttrSet("stackit_argus_instance.instance", "grafana_public_read_access"),
resource.TestCheckResourceAttrSet("stackit_argus_instance.instance", "grafana_url"),
resource.TestCheckResourceAttrSet("stackit_argus_instance.instance", "grafana_initial_admin_user"),
resource.TestCheckResourceAttrSet("stackit_argus_instance.instance", "grafana_initial_admin_password"),
resource.TestCheckResourceAttrSet("stackit_argus_instance.instance", "metrics_retention_days"),
resource.TestCheckResourceAttrSet("stackit_argus_instance.instance", "metrics_retention_days_5m_downsampling"),
resource.TestCheckResourceAttr("stackit_argus_instance.instance", "metrics_retention_days_1h_downsampling", instanceResource["metrics_retention_days_1h_downsampling"]),
resource.TestCheckResourceAttrSet("stackit_argus_instance.instance", "metrics_url"),
resource.TestCheckResourceAttrSet("stackit_argus_instance.instance", "metrics_push_url"),
resource.TestCheckResourceAttrSet("stackit_argus_instance.instance", "targets_url"),
resource.TestCheckResourceAttrSet("stackit_argus_instance.instance", "alerting_url"),
resource.TestCheckResourceAttrSet("stackit_argus_instance.instance", "logs_url"),
resource.TestCheckResourceAttrSet("stackit_argus_instance.instance", "logs_push_url"),
resource.TestCheckResourceAttrSet("stackit_argus_instance.instance", "jaeger_traces_url"),
resource.TestCheckResourceAttrSet("stackit_argus_instance.instance", "jaeger_ui_url"),
resource.TestCheckResourceAttrSet("stackit_argus_instance.instance", "otlp_traces_url"),
resource.TestCheckResourceAttrSet("stackit_argus_instance.instance", "zipkin_spans_url"),
// ACL
resource.TestCheckResourceAttr("stackit_argus_instance.instance", "acl.#", "0"),
// scrape config data
resource.TestCheckResourceAttrPair(
"stackit_argus_instance.instance", "project_id",
"stackit_argus_scrapeconfig.scrapeconfig", "project_id",
),
resource.TestCheckResourceAttrPair(
"stackit_argus_instance.instance", "instance_id",
"stackit_argus_scrapeconfig.scrapeconfig", "instance_id",
),
resource.TestCheckResourceAttr("stackit_argus_scrapeconfig.scrapeconfig", "name", scrapeConfigResource["name"]),
resource.TestCheckResourceAttr("stackit_argus_scrapeconfig.scrapeconfig", "targets.0.urls.#", "2"),
resource.TestCheckResourceAttr("stackit_argus_scrapeconfig.scrapeconfig", "metrics_path", scrapeConfigResource["metrics_path"]),
resource.TestCheckResourceAttr("stackit_argus_scrapeconfig.scrapeconfig", "scheme", scrapeConfigResource["scheme"]),
resource.TestCheckResourceAttr("stackit_argus_scrapeconfig.scrapeconfig", "scrape_interval", scrapeConfigResource["scrape_interval"]),
resource.TestCheckResourceAttr("stackit_argus_scrapeconfig.scrapeconfig", "sample_limit", scrapeConfigResource["sample_limit"]),
resource.TestCheckResourceAttr("stackit_argus_scrapeconfig.scrapeconfig", "saml2.enable_url_parameters", scrapeConfigResource["saml2_enable_url_parameters"]),
// credentials
resource.TestCheckResourceAttr("stackit_argus_credential.credential", "project_id", credentialResource["project_id"]),
resource.TestCheckResourceAttrPair(
"stackit_argus_instance.instance", "instance_id",
"stackit_argus_credential.credential", "instance_id",
),
resource.TestCheckResourceAttrSet("stackit_argus_credential.credential", "username"),
resource.TestCheckResourceAttrSet("stackit_argus_credential.credential", "password"),
),
},
// Update with empty ACL, NO metrics retention days and NO alert configs
{
Config: resourceConfig(
utils.Ptr("[]"),
nil,
nil,
nil,
nil,
instanceResource["name"],
instanceResource["plan_name"],
scrapeConfigResource["urls"],
scrapeConfigResource["saml2_enable_url_parameters"],
),
Check: resource.ComposeAggregateTestCheckFunc(
// Instance data
resource.TestCheckResourceAttr("stackit_argus_instance.instance", "project_id", instanceResource["project_id"]),
resource.TestCheckResourceAttrSet("stackit_argus_instance.instance", "instance_id"),
resource.TestCheckResourceAttr("stackit_argus_instance.instance", "name", instanceResource["name"]),
resource.TestCheckResourceAttr("stackit_argus_instance.instance", "plan_name", instanceResource["plan_name"]),
resource.TestCheckResourceAttrSet("stackit_argus_instance.instance", "dashboard_url"),
resource.TestCheckResourceAttrSet("stackit_argus_instance.instance", "is_updatable"),
resource.TestCheckResourceAttrSet("stackit_argus_instance.instance", "grafana_public_read_access"),
resource.TestCheckResourceAttrSet("stackit_argus_instance.instance", "grafana_url"),
resource.TestCheckResourceAttrSet("stackit_argus_instance.instance", "grafana_initial_admin_user"),
resource.TestCheckResourceAttrSet("stackit_argus_instance.instance", "grafana_initial_admin_password"),
resource.TestCheckResourceAttrSet("stackit_argus_instance.instance", "metrics_retention_days"),
resource.TestCheckResourceAttrSet("stackit_argus_instance.instance", "metrics_retention_days_5m_downsampling"),
resource.TestCheckResourceAttrSet("stackit_argus_instance.instance", "metrics_retention_days_1h_downsampling"),
resource.TestCheckResourceAttrSet("stackit_argus_instance.instance", "metrics_url"),
resource.TestCheckResourceAttrSet("stackit_argus_instance.instance", "metrics_push_url"),
resource.TestCheckResourceAttrSet("stackit_argus_instance.instance", "targets_url"),
resource.TestCheckResourceAttrSet("stackit_argus_instance.instance", "alerting_url"),
resource.TestCheckResourceAttrSet("stackit_argus_instance.instance", "logs_url"),
resource.TestCheckResourceAttrSet("stackit_argus_instance.instance", "logs_push_url"),
resource.TestCheckResourceAttrSet("stackit_argus_instance.instance", "jaeger_traces_url"),
resource.TestCheckResourceAttrSet("stackit_argus_instance.instance", "jaeger_ui_url"),
resource.TestCheckResourceAttrSet("stackit_argus_instance.instance", "otlp_traces_url"),
resource.TestCheckResourceAttrSet("stackit_argus_instance.instance", "zipkin_spans_url"),
// ACL
resource.TestCheckResourceAttr("stackit_argus_instance.instance", "acl.#", "0"),
// scrape config data
resource.TestCheckResourceAttrPair(
"stackit_argus_instance.instance", "project_id",
"stackit_argus_scrapeconfig.scrapeconfig", "project_id",
),
resource.TestCheckResourceAttrPair(
"stackit_argus_instance.instance", "instance_id",
"stackit_argus_scrapeconfig.scrapeconfig", "instance_id",
),
resource.TestCheckResourceAttr("stackit_argus_scrapeconfig.scrapeconfig", "name", scrapeConfigResource["name"]),
resource.TestCheckResourceAttr("stackit_argus_scrapeconfig.scrapeconfig", "targets.0.urls.#", "2"),
resource.TestCheckResourceAttr("stackit_argus_scrapeconfig.scrapeconfig", "metrics_path", scrapeConfigResource["metrics_path"]),
resource.TestCheckResourceAttr("stackit_argus_scrapeconfig.scrapeconfig", "scheme", scrapeConfigResource["scheme"]),
resource.TestCheckResourceAttr("stackit_argus_scrapeconfig.scrapeconfig", "scrape_interval", scrapeConfigResource["scrape_interval"]),
resource.TestCheckResourceAttr("stackit_argus_scrapeconfig.scrapeconfig", "sample_limit", scrapeConfigResource["sample_limit"]),
resource.TestCheckResourceAttr("stackit_argus_scrapeconfig.scrapeconfig", "saml2.enable_url_parameters", scrapeConfigResource["saml2_enable_url_parameters"]),
// credentials
resource.TestCheckResourceAttr("stackit_argus_credential.credential", "project_id", credentialResource["project_id"]),
resource.TestCheckResourceAttrPair(
"stackit_argus_instance.instance", "instance_id",
"stackit_argus_credential.credential", "instance_id",
),
resource.TestCheckResourceAttrSet("stackit_argus_credential.credential", "username"),
resource.TestCheckResourceAttrSet("stackit_argus_credential.credential", "password"),
),
},
// Data source
{
Config: fmt.Sprintf(`
%s
data "stackit_argus_instance" "instance" {
project_id = stackit_argus_instance.instance.project_id
instance_id = stackit_argus_instance.instance.instance_id
}
data "stackit_argus_scrapeconfig" "scrapeconfig" {
project_id = stackit_argus_scrapeconfig.scrapeconfig.project_id
instance_id = stackit_argus_scrapeconfig.scrapeconfig.instance_id
name = stackit_argus_scrapeconfig.scrapeconfig.name
}
`,
resourceConfig(
utils.Ptr(fmt.Sprintf(
"[%q, %q]",
instanceResource["acl-0"],
instanceResource["acl-1"],
)),
utils.Ptr(instanceResource["metrics_retention_days"]),
utils.Ptr(instanceResource["metrics_retention_days_1h_downsampling"]),
utils.Ptr(instanceResource["metrics_retention_days_5m_downsampling"]),
buildAlertConfig(buildAlertConfigReceivers(true, false, true), buildAlertConfigRoute(true), buildAlertConfigGlobal(false)),
instanceResource["name"],
instanceResource["plan_name"],
scrapeConfigResource["urls"],
scrapeConfigResource["saml2_enable_url_parameters"],
),
),
Check: resource.ComposeAggregateTestCheckFunc(
// Instance data
resource.TestCheckResourceAttr("data.stackit_argus_instance.instance", "project_id", instanceResource["project_id"]),
resource.TestCheckResourceAttrSet("data.stackit_argus_instance.instance", "instance_id"),
resource.TestCheckResourceAttr("data.stackit_argus_instance.instance", "name", instanceResource["name"]),
resource.TestCheckResourceAttr("data.stackit_argus_instance.instance", "plan_name", instanceResource["plan_name"]),
resource.TestCheckResourceAttr("data.stackit_argus_instance.instance", "acl.#", "2"),
resource.TestCheckResourceAttr("data.stackit_argus_instance.instance", "acl.0", instanceResource["acl-0"]),
resource.TestCheckResourceAttr("data.stackit_argus_instance.instance", "acl.1", instanceResource["acl-1"]),
resource.TestCheckResourceAttrPair(
"stackit_argus_instance.instance", "project_id",
"data.stackit_argus_instance.instance", "project_id",
),
resource.TestCheckResourceAttrPair(
"stackit_argus_instance.instance", "instance_id",
"data.stackit_argus_instance.instance", "instance_id",
),
// scrape config data
resource.TestCheckResourceAttrPair(
"stackit_argus_scrapeconfig.scrapeconfig", "project_id",
"data.stackit_argus_scrapeconfig.scrapeconfig", "project_id",
),
resource.TestCheckResourceAttrPair(
"stackit_argus_scrapeconfig.scrapeconfig", "instance_id",
"data.stackit_argus_scrapeconfig.scrapeconfig", "instance_id",
),
resource.TestCheckResourceAttrPair(
"stackit_argus_scrapeconfig.scrapeconfig", "name",
"data.stackit_argus_scrapeconfig.scrapeconfig", "name",
),
resource.TestCheckResourceAttr("data.stackit_argus_scrapeconfig.scrapeconfig", "name", scrapeConfigResource["name"]),
resource.TestCheckResourceAttr("data.stackit_argus_scrapeconfig.scrapeconfig", "targets.0.urls.#", "2"),
resource.TestCheckResourceAttr("data.stackit_argus_scrapeconfig.scrapeconfig", "metrics_path", scrapeConfigResource["metrics_path"]),
resource.TestCheckResourceAttr("data.stackit_argus_scrapeconfig.scrapeconfig", "scheme", scrapeConfigResource["scheme"]),
resource.TestCheckResourceAttr("data.stackit_argus_scrapeconfig.scrapeconfig", "scrape_interval", scrapeConfigResource["scrape_interval"]),
resource.TestCheckResourceAttr("stackit_argus_scrapeconfig.scrapeconfig", "sample_limit", scrapeConfigResource["sample_limit"]),
resource.TestCheckResourceAttr("data.stackit_argus_scrapeconfig.scrapeconfig", "saml2.enable_url_parameters", scrapeConfigResource["saml2_enable_url_parameters"]),
),
},
// Import 1
{
ResourceName: "stackit_argus_instance.instance",
ImportStateIdFunc: func(s *terraform.State) (string, error) {
r, ok := s.RootModule().Resources["stackit_argus_instance.instance"]
if !ok {
return "", fmt.Errorf("couldn't find resource stackit_argus_instance.instance")
}
instanceId, ok := r.Primary.Attributes["instance_id"]
if !ok {
return "", fmt.Errorf("couldn't find attribute instance_id")
}
return fmt.Sprintf("%s,%s", testutil.ProjectId, instanceId), nil
},
ImportState: true,
ImportStateVerify: true,
},
// Import 2
{
ResourceName: "stackit_argus_scrapeconfig.scrapeconfig",
ImportStateIdFunc: func(s *terraform.State) (string, error) {
r, ok := s.RootModule().Resources["stackit_argus_scrapeconfig.scrapeconfig"]
if !ok {
return "", fmt.Errorf("couldn't find resource stackit_argus_scrapeconfig.scrapeconfig")
}
instanceId, ok := r.Primary.Attributes["instance_id"]
if !ok {
return "", fmt.Errorf("couldn't find attribute instance_id")
}
name, ok := r.Primary.Attributes["name"]
if !ok {
return "", fmt.Errorf("couldn't find attribute name")
}
return fmt.Sprintf("%s,%s,%s", testutil.ProjectId, instanceId, name), nil
},
ImportState: true,
ImportStateVerify: true,
},
// Update
{
Config: resourceConfig(
utils.Ptr(fmt.Sprintf(
"[%q, %q]",
instanceResource["acl-0"],
instanceResource["acl-1-updated"],
)),
utils.Ptr(instanceResource["metrics_retention_days"]),
utils.Ptr(instanceResource["metrics_retention_days_1h_downsampling"]),
utils.Ptr(instanceResource["metrics_retention_days_5m_downsampling"]),
buildAlertConfig(buildAlertConfigReceivers(true, false, true), buildAlertConfigRoute(true), buildAlertConfigGlobal(false)),
fmt.Sprintf("%s-new", instanceResource["name"]),
instanceResource["new_plan_name"],
"",
"true",
),
Check: resource.ComposeAggregateTestCheckFunc(
// Instance
resource.TestCheckResourceAttr("stackit_argus_instance.instance", "project_id", instanceResource["project_id"]),
resource.TestCheckResourceAttrSet("stackit_argus_instance.instance", "instance_id"),
resource.TestCheckResourceAttr("stackit_argus_instance.instance", "name", instanceResource["name"]+"-new"),
resource.TestCheckResourceAttr("stackit_argus_instance.instance", "plan_name", instanceResource["new_plan_name"]),
resource.TestCheckResourceAttr("stackit_argus_instance.instance", "acl.#", "2"),
resource.TestCheckResourceAttr("stackit_argus_instance.instance", "acl.0", instanceResource["acl-0"]),
resource.TestCheckResourceAttr("stackit_argus_instance.instance", "acl.1", instanceResource["acl-1-updated"]),
// Alert Config
resource.TestCheckResourceAttr("stackit_argus_instance.instance", "alert_config.route.group_by.#", "1"),
resource.TestCheckResourceAttr("stackit_argus_instance.instance", "alert_config.route.group_by.0", "alertname"),
resource.TestCheckResourceAttr("stackit_argus_instance.instance", "alert_config.route.group_interval", "10m"),
resource.TestCheckResourceAttr("stackit_argus_instance.instance", "alert_config.route.group_wait", "1m"),
resource.TestCheckResourceAttr("stackit_argus_instance.instance", "alert_config.route.repeat_interval", "1h"),
resource.TestCheckResourceAttr("stackit_argus_instance.instance", "alert_config.global.resolve_timeout", "5m"),
resource.TestCheckResourceAttr("stackit_argus_instance.instance", "alert_config.global.opsgenie_api_key", "example-api-key"),
resource.TestCheckResourceAttr("stackit_argus_instance.instance", "alert_config.global.opsgenie_api_url", "https://api.eu.opsgenie.com"),
resource.TestCheckResourceAttr("stackit_argus_instance.instance", "alert_config.route.receiver", "OpsGenieReceiverInfo"),
resource.TestCheckResourceAttr("stackit_argus_instance.instance", "alert_config.route.group_by.#", "1"),
resource.TestCheckResourceAttr("stackit_argus_instance.instance", "alert_config.route.group_by.0", "alertname"),
resource.TestCheckResourceAttr("stackit_argus_instance.instance", "alert_config.route.group_interval", "10m"),
resource.TestCheckResourceAttr("stackit_argus_instance.instance", "alert_config.route.group_wait", "1m"),
resource.TestCheckResourceAttr("stackit_argus_instance.instance", "alert_config.route.repeat_interval", "1h"),
resource.TestCheckResourceAttr("stackit_argus_instance.instance", "alert_config.route.routes.#", "2"),
resource.TestCheckResourceAttr("stackit_argus_instance.instance", "alert_config.route.routes.0.match.severity", "critical"),
resource.TestCheckResourceAttr("stackit_argus_instance.instance", "alert_config.route.routes.0.receiver", "OpsGenieReceiverInfo"),
resource.TestCheckResourceAttr("stackit_argus_instance.instance", "alert_config.route.routes.1.match.severity", "warning"),
resource.TestCheckResourceAttr("stackit_argus_instance.instance", "alert_config.route.routes.1.receiver", "WebhookReceiverInfo"),
resource.TestCheckResourceAttr("stackit_argus_instance.instance", "alert_config.receivers.#", "2"),
resource.TestCheckResourceAttr("stackit_argus_instance.instance", "alert_config.receivers.0.name", "OpsGenieReceiverInfo"),
resource.TestCheckResourceAttr("stackit_argus_instance.instance", "alert_config.receivers.0.opsgenie_configs.#", "1"),
resource.TestCheckResourceAttr("stackit_argus_instance.instance", "alert_config.receivers.0.opsgenie_configs.0.tags", "iam,argus-alert"),
resource.TestCheckResourceAttr("stackit_argus_instance.instance", "alert_config.receivers.0.opsgenie_configs.0.api_key",
"example-api-key"),
resource.TestCheckResourceAttr("stackit_argus_instance.instance", "alert_config.receivers.1.name", "WebhookReceiverInfo"),
resource.TestCheckResourceAttr("stackit_argus_instance.instance", "alert_config.receivers.1.webhooks_configs.#", "1"),
resource.TestCheckResourceAttr("stackit_argus_instance.instance", "alert_config.receivers.1.webhooks_configs.0.url", "https://example.com"),
resource.TestCheckResourceAttr("stackit_argus_instance.instance", "alert_config.receivers.1.webhooks_configs.0.ms_teams", "true"),
// Scrape Config
resource.TestCheckResourceAttr("stackit_argus_scrapeconfig.scrapeconfig", "name", scrapeConfigResource["name"]),
resource.TestCheckResourceAttr("stackit_argus_scrapeconfig.scrapeconfig", "targets.#", "0"),
resource.TestCheckResourceAttr("stackit_argus_scrapeconfig.scrapeconfig", "metrics_path", scrapeConfigResource["metrics_path"]),
resource.TestCheckResourceAttr("stackit_argus_scrapeconfig.scrapeconfig", "scheme", scrapeConfigResource["scheme"]),
resource.TestCheckResourceAttr("stackit_argus_scrapeconfig.scrapeconfig", "scrape_interval", scrapeConfigResource["scrape_interval"]),
resource.TestCheckResourceAttr("stackit_argus_scrapeconfig.scrapeconfig", "sample_limit", scrapeConfigResource["sample_limit"]),
resource.TestCheckResourceAttr("stackit_argus_scrapeconfig.scrapeconfig", "saml2.%", "1"),
resource.TestCheckResourceAttr("stackit_argus_scrapeconfig.scrapeconfig", "saml2.enable_url_parameters", "true"),
// Credentials
resource.TestCheckResourceAttrSet("stackit_argus_credential.credential", "username"),
resource.TestCheckResourceAttrSet("stackit_argus_credential.credential", "password"),
),
},
// Update and remove saml2 attribute
{
Config: fmt.Sprintf(`
%s
resource "stackit_argus_instance" "instance" {
project_id = "%s"
name = "%s"
plan_name = "%s"
}
resource "stackit_argus_scrapeconfig" "scrapeconfig" {
project_id = stackit_argus_instance.instance.project_id
instance_id = stackit_argus_instance.instance.instance_id
name = "%s"
targets = [%s]
scrape_interval = "%s"
sample_limit = %s
metrics_path = "%s"
saml2 = {
enable_url_parameters = false
}
}
`,
testutil.ArgusProviderConfig(),
instanceResource["project_id"],
instanceResource["name"],
instanceResource["new_plan_name"],
scrapeConfigResource["name"],
scrapeConfigResource["urls"],
scrapeConfigResource["scrape_interval"],
scrapeConfigResource["sample_limit"],
scrapeConfigResource["metrics_path"],
),
Check: resource.ComposeAggregateTestCheckFunc(
// Instance
resource.TestCheckResourceAttr("stackit_argus_instance.instance", "project_id", instanceResource["project_id"]),
resource.TestCheckResourceAttrSet("stackit_argus_instance.instance", "instance_id"),
resource.TestCheckResourceAttr("stackit_argus_instance.instance", "name", instanceResource["name"]),
resource.TestCheckResourceAttr("stackit_argus_instance.instance", "plan_name", instanceResource["new_plan_name"]),
// ACL
resource.TestCheckResourceAttr("stackit_argus_instance.instance", "acl.#", "0"),
// Scrape Config
resource.TestCheckResourceAttr("stackit_argus_scrapeconfig.scrapeconfig", "name", scrapeConfigResource["name"]),
resource.TestCheckResourceAttr("stackit_argus_scrapeconfig.scrapeconfig", "targets.#", "1"),
resource.TestCheckResourceAttr("stackit_argus_scrapeconfig.scrapeconfig", "metrics_path", scrapeConfigResource["metrics_path"]),
resource.TestCheckResourceAttr("stackit_argus_scrapeconfig.scrapeconfig", "scheme", scrapeConfigResource["scheme"]),
resource.TestCheckResourceAttr("stackit_argus_scrapeconfig.scrapeconfig", "scrape_interval", scrapeConfigResource["scrape_interval"]),
resource.TestCheckResourceAttr("stackit_argus_scrapeconfig.scrapeconfig", "sample_limit", scrapeConfigResource["sample_limit"]),
resource.TestCheckResourceAttr("stackit_argus_scrapeconfig.scrapeconfig", "saml2.%", "1"),
resource.TestCheckResourceAttr("stackit_argus_scrapeconfig.scrapeconfig", "saml2.enable_url_parameters", "false"),
),
},
// Deletion is done by the framework implicitly
},
})
}
func testAccCheckArgusDestroy(s *terraform.State) error {
ctx := context.Background()
var client *argus.APIClient
var err error
if testutil.ArgusCustomEndpoint == "" {
client, err = argus.NewAPIClient(
config.WithRegion("eu01"),
)
} else {
client, err = argus.NewAPIClient(
config.WithEndpoint(testutil.ArgusCustomEndpoint),
)
}
if err != nil {
return fmt.Errorf("creating client: %w", err)
}
instancesToDestroy := []string{}
for _, rs := range s.RootModule().Resources {
if rs.Type != "stackit_argus_instance" {
continue
}
// instance terraform ID: = "[project_id],[instance_id],[name]"
instanceId := strings.Split(rs.Primary.ID, core.Separator)[1]
instancesToDestroy = append(instancesToDestroy, instanceId)
}
instancesResp, err := client.ListInstances(ctx, testutil.ProjectId).Execute()
if err != nil {
return fmt.Errorf("getting instancesResp: %w", err)
}
instances := *instancesResp.Instances
for i := range instances {
if utils.Contains(instancesToDestroy, *instances[i].Id) {
if *instances[i].Status != wait.DeleteSuccess {
_, err := client.DeleteInstanceExecute(ctx, testutil.ProjectId, *instances[i].Id)
if err != nil {
return fmt.Errorf("destroying instance %s during CheckDestroy: %w", *instances[i].Id, err)
}
_, err = wait.DeleteInstanceWaitHandler(ctx, client, testutil.ProjectId, *instances[i].Id).WaitWithContext(ctx)
if err != nil {
return fmt.Errorf("destroying instance %s during CheckDestroy: waiting for deletion %w", *instances[i].Id, err)
}
}
}
}
return nil
}

View file

@ -1,24 +0,0 @@
package argus
const exampleMoveToObservability = "## Example move\n" +
"Example to move the deprecated `stackit_argus_credential` resource to the new `stackit_observability_credential` resource:" + "\n" +
"1. Add a new `stackit_observability_credential` resource with the same values like your previous `stackit_argus_credential` resource." + "\n" +
"1. Add a moved block which reference the `stackit_argus_credential` and `stackit_observability_credential` resource." + "\n" +
"1. Remove your old `stackit_argus_credential` resource and run `$ terraform apply`." + "\n" +
"```terraform" +
`
resource "stackit_argus_credential" "example" {
project_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
instance_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
}
moved {
from = stackit_argus_credential.example
to = stackit_observability_credential.example
}
resource "stackit_observability_credential" "example" {
project_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
instance_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
}
` + "```" + "\n"

View file

@ -1,264 +0,0 @@
package argus
import (
"context"
"fmt"
"net/http"
"strings"
"github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
"github.com/hashicorp/terraform-plugin-framework/resource"
"github.com/hashicorp/terraform-plugin-framework/resource/schema"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
"github.com/hashicorp/terraform-plugin-framework/schema/validator"
"github.com/hashicorp/terraform-plugin-framework/types"
"github.com/hashicorp/terraform-plugin-log/tflog"
"github.com/stackitcloud/stackit-sdk-go/core/config"
"github.com/stackitcloud/stackit-sdk-go/core/oapierror"
"github.com/stackitcloud/stackit-sdk-go/services/argus"
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/core"
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/validate"
)
// Ensure the implementation satisfies the expected interfaces.
var (
_ resource.Resource = &credentialResource{}
_ resource.ResourceWithConfigure = &credentialResource{}
)
type Model struct {
Id types.String `tfsdk:"id"`
ProjectId types.String `tfsdk:"project_id"`
InstanceId types.String `tfsdk:"instance_id"`
Username types.String `tfsdk:"username"`
Password types.String `tfsdk:"password"`
}
// NewCredentialResource is a helper function to simplify the provider implementation.
func NewCredentialResource() resource.Resource {
return &credentialResource{}
}
// credentialResource is the resource implementation.
type credentialResource struct {
client *argus.APIClient
}
// Metadata returns the resource type name.
func (r *credentialResource) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
resp.TypeName = req.ProviderTypeName + "_argus_credential"
}
// Configure adds the provider configured client to the resource.
func (r *credentialResource) Configure(ctx context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) {
// Prevent panic if the provider has not been configured.
if req.ProviderData == nil {
return
}
providerData, ok := req.ProviderData.(core.ProviderData)
if !ok {
core.LogAndAddError(ctx, &resp.Diagnostics, "Error configuring API client", fmt.Sprintf("Expected configure type stackit.ProviderData, got %T", req.ProviderData))
return
}
var apiClient *argus.APIClient
var err error
if providerData.ArgusCustomEndpoint != "" {
apiClient, err = argus.NewAPIClient(
config.WithCustomAuth(providerData.RoundTripper),
config.WithEndpoint(providerData.ArgusCustomEndpoint),
)
} else {
apiClient, err = argus.NewAPIClient(
config.WithCustomAuth(providerData.RoundTripper),
config.WithRegion(providerData.GetRegion()),
)
}
if err != nil {
core.LogAndAddError(ctx, &resp.Diagnostics, "Error configuring API client", fmt.Sprintf("Configuring client: %v. This is an error related to the provider configuration, not to the resource configuration", err))
return
}
r.client = apiClient
tflog.Info(ctx, "Argus credential client configured")
}
var (
descriptions = map[string]string{
"main": "Argus credential resource schema. Must have a `region` specified in the provider configuration.",
"deprecation_message": "The `stackit_argus_credential` resource has been deprecated and will be removed after February 26th 2025. " +
"Please use `stackit_observability_credential` instead, which offers the exact same functionality.",
}
Schema = schema.Schema{
Description: fmt.Sprintf("%s\n%s", descriptions["main"], descriptions["deprecation_message"]),
MarkdownDescription: fmt.Sprintf("%s\n\n!> %s\n\n%s", descriptions["main"], descriptions["deprecation_message"], exampleMoveToObservability),
DeprecationMessage: descriptions["deprecation_message"],
Attributes: map[string]schema.Attribute{
"id": schema.StringAttribute{
Description: "Terraform's internal resource ID. It is structured as \"`project_id`,`instance_id`,`username`\".",
Computed: true,
PlanModifiers: []planmodifier.String{
stringplanmodifier.UseStateForUnknown(),
},
},
"project_id": schema.StringAttribute{
Description: "STACKIT project ID to which the credential is associated.",
Required: true,
Validators: []validator.String{
validate.UUID(),
},
PlanModifiers: []planmodifier.String{
stringplanmodifier.RequiresReplace(),
},
},
"instance_id": schema.StringAttribute{
Description: "The Argus Instance ID the credential belongs to.",
Required: true,
Validators: []validator.String{
validate.UUID(),
},
PlanModifiers: []planmodifier.String{
stringplanmodifier.RequiresReplace(),
},
},
"username": schema.StringAttribute{
Description: "Credential username",
Computed: true,
Validators: []validator.String{
stringvalidator.LengthAtLeast(1),
},
},
"password": schema.StringAttribute{
Description: "Credential password",
Computed: true,
Sensitive: true,
Validators: []validator.String{
stringvalidator.LengthAtLeast(1),
},
PlanModifiers: []planmodifier.String{
stringplanmodifier.UseStateForUnknown(),
},
},
},
}
)
func (r *credentialResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) {
resp.Schema = Schema
}
// Create creates the resource and sets the initial Terraform state.
func (r *credentialResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { // nolint:gocritic // function signature required by Terraform
var model Model
diags := req.Plan.Get(ctx, &model)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
projectId := model.ProjectId.ValueString()
instanceId := model.InstanceId.ValueString()
got, err := r.client.CreateCredentials(ctx, instanceId, projectId).Execute()
if err != nil {
core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating credential", fmt.Sprintf("Calling API: %v", err))
return
}
err = mapFields(got.Credentials, &model)
if err != nil {
core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating credential", fmt.Sprintf("Processing API payload: %v", err))
return
}
diags = resp.State.Set(ctx, &model)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
tflog.Info(ctx, "Argus credential created")
}
func mapFields(r *argus.Credentials, model *Model) error {
if r == nil {
return fmt.Errorf("response input is nil")
}
if model == nil {
return fmt.Errorf("model input is nil")
}
var userName string
if model.Username.ValueString() != "" {
userName = model.Username.ValueString()
} else if r.Username != nil {
userName = *r.Username
} else {
return fmt.Errorf("username id not present")
}
idParts := []string{
model.ProjectId.ValueString(),
model.InstanceId.ValueString(),
userName,
}
model.Id = types.StringValue(
strings.Join(idParts, core.Separator),
)
model.Username = types.StringPointerValue(r.Username)
model.Password = types.StringPointerValue(r.Password)
return nil
}
// Read refreshes the Terraform state with the latest data.
func (r *credentialResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { // nolint:gocritic // function signature required by Terraform
var model Model
diags := req.State.Get(ctx, &model)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
projectId := model.ProjectId.ValueString()
instanceId := model.InstanceId.ValueString()
userName := model.Username.ValueString()
_, err := r.client.GetCredentials(ctx, instanceId, projectId, userName).Execute()
if err != nil {
oapiErr, ok := err.(*oapierror.GenericOpenAPIError) //nolint:errorlint //complaining that error.As should be used to catch wrapped errors, but this error should not be wrapped
if ok && oapiErr.StatusCode == http.StatusNotFound {
resp.State.RemoveResource(ctx)
return
}
core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading credential", fmt.Sprintf("Calling API: %v", err))
return
}
diags = resp.State.Set(ctx, model)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
tflog.Info(ctx, "Argus credential read")
}
func (r *credentialResource) Update(ctx context.Context, _ resource.UpdateRequest, resp *resource.UpdateResponse) { // nolint:gocritic // function signature required by Terraform
// Update shouldn't be called
core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating credential", "Credential can't be updated")
}
// Delete deletes the resource and removes the Terraform state on success.
func (r *credentialResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { // nolint:gocritic // function signature required by Terraform
// Retrieve values from state
var model Model
diags := req.State.Get(ctx, &model)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
projectId := model.ProjectId.ValueString()
instanceId := model.InstanceId.ValueString()
userName := model.Username.ValueString()
_, err := r.client.DeleteCredentials(ctx, instanceId, projectId, userName).Execute()
if err != nil {
core.LogAndAddError(ctx, &resp.Diagnostics, "Error deleting credential", fmt.Sprintf("Calling API: %v", err))
return
}
tflog.Info(ctx, "Argus credential deleted")
}

View file

@ -1,77 +0,0 @@
package argus
import (
"testing"
"github.com/google/go-cmp/cmp"
"github.com/hashicorp/terraform-plugin-framework/types"
"github.com/stackitcloud/stackit-sdk-go/core/utils"
"github.com/stackitcloud/stackit-sdk-go/services/argus"
)
func TestMapFields(t *testing.T) {
tests := []struct {
description string
input *argus.Credentials
expected Model
isValid bool
}{
{
"ok",
&argus.Credentials{
Username: utils.Ptr("username"),
Password: utils.Ptr("password"),
},
Model{
Id: types.StringValue("pid,iid,username"),
ProjectId: types.StringValue("pid"),
InstanceId: types.StringValue("iid"),
Username: types.StringValue("username"),
Password: types.StringValue("password"),
},
true,
},
{
"response_nil_fail",
nil,
Model{},
false,
},
{
"response_fields_nil_fail",
&argus.Credentials{
Password: nil,
Username: nil,
},
Model{},
false,
},
{
"no_resource_id",
&argus.Credentials{},
Model{},
false,
},
}
for _, tt := range tests {
t.Run(tt.description, func(t *testing.T) {
state := &Model{
ProjectId: tt.expected.ProjectId,
InstanceId: tt.expected.InstanceId,
}
err := mapFields(tt.input, state)
if !tt.isValid && err == nil {
t.Fatalf("Should have failed")
}
if tt.isValid && err != nil {
t.Fatalf("Should not have failed: %v", err)
}
if tt.isValid {
diff := cmp.Diff(state, &tt.expected)
if diff != "" {
t.Fatalf("Data does not match: %s", diff)
}
}
})
}
}

View file

@ -1,34 +0,0 @@
package argus
const exampleMoveToObservability = "## Example move\n" +
"Example to move the deprecated `stackit_argus_instance` resource to the new`stackit_observability_instance` resource:" + "\n" +
"1. Add a new `stackit_observability_instance` resource with the same values like your previous `stackit_argus_instance` resource." + "\n" +
"1. Add a moved block which reference the `stackit_argus_instance` and `stackit_observability_instance` resource." + "\n" +
"1. Remove your old `stackit_argus_instance` resource and run `$ terraform apply`." + "\n" +
"```terraform" +
`
resource "stackit_argus_instance" "example" {
project_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
name = "example-instance"
plan_name = "Monitoring-Medium-EU01"
acl = ["1.1.1.1/32", "2.2.2.2/32"]
metrics_retention_days = 7
metrics_retention_days_5m_downsampling = 30
metrics_retention_days_1h_downsampling = 365
}
moved {
from = stackit_argus_instance.example
to = stackit_observability_instance.example
}
resource "stackit_observability_instance" "example" {
project_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
name = "example-instance"
plan_name = "Monitoring-Medium-EU01"
acl = ["1.1.1.1/32", "2.2.2.2/32"]
metrics_retention_days = 7
metrics_retention_days_5m_downsampling = 30
metrics_retention_days_1h_downsampling = 365
}
` + "```" + "\n"

View file

@ -1,442 +0,0 @@
package argus
import (
"context"
"fmt"
"net/http"
"github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
"github.com/hashicorp/terraform-plugin-framework/datasource"
"github.com/hashicorp/terraform-plugin-framework/datasource/schema"
"github.com/hashicorp/terraform-plugin-framework/schema/validator"
"github.com/hashicorp/terraform-plugin-framework/types"
"github.com/hashicorp/terraform-plugin-log/tflog"
"github.com/stackitcloud/stackit-sdk-go/core/config"
"github.com/stackitcloud/stackit-sdk-go/core/oapierror"
"github.com/stackitcloud/stackit-sdk-go/services/argus"
"github.com/stackitcloud/stackit-sdk-go/services/argus/wait"
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/core"
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/validate"
)
// Ensure the implementation satisfies the expected interfaces.
var (
_ datasource.DataSource = &instanceDataSource{}
)
// NewInstanceDataSource is a helper function to simplify the provider implementation.
func NewInstanceDataSource() datasource.DataSource {
return &instanceDataSource{}
}
// instanceDataSource is the data source implementation.
type instanceDataSource struct {
client *argus.APIClient
}
// Metadata returns the data source type name.
func (d *instanceDataSource) Metadata(_ context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) {
resp.TypeName = req.ProviderTypeName + "_argus_instance"
}
func (d *instanceDataSource) Configure(ctx context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) {
// Prevent panic if the provider has not been configured.
if req.ProviderData == nil {
return
}
var apiClient *argus.APIClient
var err error
providerData, ok := req.ProviderData.(core.ProviderData)
if !ok {
core.LogAndAddError(ctx, &resp.Diagnostics, "Error configuring API client", fmt.Sprintf("Expected configure type stackit.ProviderData, got %T", req.ProviderData))
return
}
if providerData.ArgusCustomEndpoint != "" {
apiClient, err = argus.NewAPIClient(
config.WithCustomAuth(providerData.RoundTripper),
config.WithEndpoint(providerData.ArgusCustomEndpoint),
)
} else {
apiClient, err = argus.NewAPIClient(
config.WithCustomAuth(providerData.RoundTripper),
config.WithRegion(providerData.GetRegion()),
)
}
if err != nil {
core.LogAndAddError(ctx, &resp.Diagnostics, "Error configuring API client", fmt.Sprintf("Configuring client: %v. This is an error related to the provider configuration, not to the data source configuration", err))
return
}
d.client = apiClient
tflog.Info(ctx, "Argus instance client configured")
}
// Schema defines the schema for the data source.
func (d *instanceDataSource) Schema(_ context.Context, _ datasource.SchemaRequest, resp *datasource.SchemaResponse) {
descriptions := map[string]string{
"main": "Argus instance data source schema. Must have a `region` specified in the provider configuration.",
"deprecation_message": "The `stackit_argus_instance` data source has been deprecated and will be removed after February 26th 2025. " +
"Please use `stackit_observability_instance` instead, which offers the exact same functionality.",
}
resp.Schema = schema.Schema{
Description: fmt.Sprintf("%s\n%s", descriptions["main"], descriptions["deprecation_message"]),
MarkdownDescription: fmt.Sprintf("%s\n\n!> %s", descriptions["main"], descriptions["deprecation_message"]),
DeprecationMessage: descriptions["deprecation_message"],
Attributes: map[string]schema.Attribute{
"id": schema.StringAttribute{
Description: "Terraform's internal data source ID. It is structured as \"`project_id`,`instance_id`\".",
Computed: true,
},
"project_id": schema.StringAttribute{
Description: "STACKIT project ID to which the instance is associated.",
Required: true,
Validators: []validator.String{
validate.UUID(),
validate.NoSeparator(),
},
},
"instance_id": schema.StringAttribute{
Description: "The Argus instance ID.",
Required: true,
Validators: []validator.String{
validate.UUID(),
validate.NoSeparator(),
},
},
"name": schema.StringAttribute{
Description: "The name of the Argus instance.",
Computed: true,
Validators: []validator.String{
stringvalidator.LengthAtLeast(1),
stringvalidator.LengthAtMost(300),
},
},
"plan_name": schema.StringAttribute{
Description: "Specifies the Argus plan. E.g. `Monitoring-Medium-EU01`.",
Computed: true,
Validators: []validator.String{
stringvalidator.LengthAtLeast(1),
stringvalidator.LengthAtMost(200),
},
},
"plan_id": schema.StringAttribute{
Description: "The Argus plan ID.",
Computed: true,
Validators: []validator.String{
validate.UUID(),
},
},
"parameters": schema.MapAttribute{
Description: "Additional parameters.",
Computed: true,
ElementType: types.StringType,
},
"dashboard_url": schema.StringAttribute{
Description: "Specifies Argus instance dashboard URL.",
Computed: true,
},
"is_updatable": schema.BoolAttribute{
Description: "Specifies if the instance can be updated.",
Computed: true,
},
"grafana_public_read_access": schema.BoolAttribute{
Description: "If true, anyone can access Grafana dashboards without logging in.",
Computed: true,
},
"grafana_url": schema.StringAttribute{
Description: "Specifies Grafana URL.",
Computed: true,
},
"grafana_initial_admin_user": schema.StringAttribute{
Description: "Specifies an initial Grafana admin username.",
Computed: true,
},
"grafana_initial_admin_password": schema.StringAttribute{
Description: "Specifies an initial Grafana admin password.",
Computed: true,
Sensitive: true,
},
"metrics_retention_days": schema.Int64Attribute{
Description: "Specifies for how many days the raw metrics are kept.",
Computed: true,
},
"metrics_retention_days_5m_downsampling": schema.Int64Attribute{
Description: "Specifies for how many days the 5m downsampled metrics are kept. must be less than the value of the general retention. Default is set to `0` (disabled).",
Computed: true,
},
"metrics_retention_days_1h_downsampling": schema.Int64Attribute{
Description: "Specifies for how many days the 1h downsampled metrics are kept. must be less than the value of the 5m downsampling retention. Default is set to `0` (disabled).",
Computed: true,
},
"metrics_url": schema.StringAttribute{
Description: "Specifies metrics URL.",
Computed: true,
},
"metrics_push_url": schema.StringAttribute{
Description: "Specifies URL for pushing metrics.",
Computed: true,
},
"targets_url": schema.StringAttribute{
Description: "Specifies Targets URL.",
Computed: true,
},
"alerting_url": schema.StringAttribute{
Description: "Specifies Alerting URL.",
Computed: true,
},
"logs_url": schema.StringAttribute{
Description: "Specifies Logs URL.",
Computed: true,
},
"logs_push_url": schema.StringAttribute{
Description: "Specifies URL for pushing logs.",
Computed: true,
},
"jaeger_traces_url": schema.StringAttribute{
Computed: true,
},
"jaeger_ui_url": schema.StringAttribute{
Computed: true,
},
"otlp_traces_url": schema.StringAttribute{
Computed: true,
},
"zipkin_spans_url": schema.StringAttribute{
Computed: true,
},
"acl": schema.SetAttribute{
Description: "The access control list for this instance. Each entry is an IP address range that is permitted to access, in CIDR notation.",
ElementType: types.StringType,
Computed: true,
},
"alert_config": schema.SingleNestedAttribute{
Description: "Alert configuration for the instance.",
Computed: true,
Attributes: map[string]schema.Attribute{
"receivers": schema.ListNestedAttribute{
Description: "List of alert receivers.",
Computed: true,
NestedObject: schema.NestedAttributeObject{
Attributes: map[string]schema.Attribute{
"name": schema.StringAttribute{
Description: "Name of the receiver.",
Computed: true,
},
"email_configs": schema.ListNestedAttribute{
Description: "List of email configurations.",
Computed: true,
NestedObject: schema.NestedAttributeObject{
Attributes: map[string]schema.Attribute{
"auth_identity": schema.StringAttribute{
Description: "SMTP authentication information. Must be a valid email address",
Computed: true,
},
"auth_password": schema.StringAttribute{
Description: "SMTP authentication password.",
Computed: true,
},
"auth_username": schema.StringAttribute{
Description: "SMTP authentication username.",
Computed: true,
},
"from": schema.StringAttribute{
Description: "The sender email address. Must be a valid email address",
Computed: true,
},
"smart_host": schema.StringAttribute{
Description: "The SMTP host through which emails are sent.",
Computed: true,
},
"to": schema.StringAttribute{
Description: "The email address to send notifications to. Must be a valid email address",
Computed: true,
},
},
},
},
"opsgenie_configs": schema.ListNestedAttribute{
Description: "List of OpsGenie configurations.",
Computed: true,
NestedObject: schema.NestedAttributeObject{
Attributes: map[string]schema.Attribute{
"api_key": schema.StringAttribute{
Description: "The API key for OpsGenie.",
Computed: true,
},
"api_url": schema.StringAttribute{
Description: "The host to send OpsGenie API requests to. Must be a valid URL",
Computed: true,
},
"tags": schema.StringAttribute{
Description: "Comma separated list of tags attached to the notifications.",
Computed: true,
},
},
},
},
"webhooks_configs": schema.ListNestedAttribute{
Description: "List of Webhooks configurations.",
Computed: true,
NestedObject: schema.NestedAttributeObject{
Attributes: map[string]schema.Attribute{
"url": schema.StringAttribute{
Description: "The endpoint to send HTTP POST requests to. Must be a valid URL",
Computed: true,
},
"ms_teams": schema.BoolAttribute{
Description: "Microsoft Teams webhooks require special handling, set this to true if the webhook is for Microsoft Teams.",
Computed: true,
},
},
},
},
},
},
},
"route": schema.SingleNestedAttribute{
Description: "The route for the alert.",
Computed: true,
Attributes: map[string]schema.Attribute{
"group_by": schema.ListAttribute{
Description: "The labels by which incoming alerts are grouped together. For example, multiple alerts coming in for cluster=A and alertname=LatencyHigh would be batched into a single group. To aggregate by all possible labels use the special value '...' as the sole label name, for example: group_by: ['...']. This effectively disables aggregation entirely, passing through all alerts as-is. This is unlikely to be what you want, unless you have a very low alert volume or your upstream notification system performs its own grouping.",
Computed: true,
ElementType: types.StringType,
},
"group_interval": schema.StringAttribute{
Description: "How long to wait before sending a notification about new alerts that are added to a group of alerts for which an initial notification has already been sent. (Usually ~5m or more.)",
Computed: true,
},
"group_wait": schema.StringAttribute{
Description: "How long to initially wait to send a notification for a group of alerts. Allows to wait for an inhibiting alert to arrive or collect more initial alerts for the same group. (Usually ~0s to few minutes.) .",
Computed: true,
},
"match": schema.MapAttribute{
Description: "A set of equality matchers an alert has to fulfill to match the node.",
Computed: true,
ElementType: types.StringType,
},
"match_regex": schema.MapAttribute{
Description: "A set of regex-matchers an alert has to fulfill to match the node.",
Computed: true,
ElementType: types.StringType,
},
"receiver": schema.StringAttribute{
Description: "The name of the receiver to route the alerts to.",
Computed: true,
},
"repeat_interval": schema.StringAttribute{
Description: "How long to wait before sending a notification again if it has already been sent successfully for an alert. (Usually ~3h or more).",
Computed: true,
},
"routes": getDatasourceRouteNestedObject(),
},
},
"global": schema.SingleNestedAttribute{
Description: "Global configuration for the alerts.",
Computed: true,
Attributes: map[string]schema.Attribute{
"opsgenie_api_key": schema.StringAttribute{
Description: "The API key for OpsGenie.",
Computed: true,
Sensitive: true,
},
"opsgenie_api_url": schema.StringAttribute{
Description: "The host to send OpsGenie API requests to. Must be a valid URL",
Computed: true,
},
"resolve_timeout": schema.StringAttribute{
Description: "The default value used by alertmanager if the alert does not include EndsAt. After this time passes, it can declare the alert as resolved if it has not been updated. This has no impact on alerts from Prometheus, as they always include EndsAt.",
Computed: true,
},
"smtp_auth_identity": schema.StringAttribute{
Description: "SMTP authentication information. Must be a valid email address",
Computed: true,
},
"smtp_auth_password": schema.StringAttribute{
Description: "SMTP Auth using LOGIN and PLAIN.",
Computed: true,
Sensitive: true,
},
"smtp_auth_username": schema.StringAttribute{
Description: "SMTP Auth using CRAM-MD5, LOGIN and PLAIN. If empty, Alertmanager doesn't authenticate to the SMTP server.",
Computed: true,
},
"smtp_from": schema.StringAttribute{
Description: "The default SMTP From header field. Must be a valid email address",
Computed: true,
},
"smtp_smart_host": schema.StringAttribute{
Description: "The default SMTP smarthost used for sending emails, including port number. Port number usually is 25, or 587 for SMTP over TLS (sometimes referred to as STARTTLS).",
Computed: true,
},
},
},
},
},
},
}
}
// Read refreshes the Terraform state with the latest data.
func (d *instanceDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { // nolint:gocritic // function signature required by Terraform
var model Model
diags := req.Config.Get(ctx, &model)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
projectId := model.ProjectId.ValueString()
instanceId := model.InstanceId.ValueString()
instanceResp, err := d.client.GetInstance(ctx, instanceId, projectId).Execute()
if err != nil {
oapiErr, ok := err.(*oapierror.GenericOpenAPIError) //nolint:errorlint //complaining that error.As should be used to catch wrapped errors, but this error should not be wrapped
if ok && oapiErr.StatusCode == http.StatusNotFound {
resp.State.RemoveResource(ctx)
}
core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading instance", fmt.Sprintf("Calling API: %v", err))
return
}
if instanceResp != nil && instanceResp.Status != nil && *instanceResp.Status == wait.DeleteSuccess {
resp.State.RemoveResource(ctx)
core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading instance", "Instance was deleted successfully")
return
}
aclListResp, err := d.client.ListACL(ctx, instanceId, projectId).Execute()
if err != nil {
core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading instance", fmt.Sprintf("Calling API to list ACL data: %v", err))
return
}
alertConfigResp, err := d.client.GetAlertConfigs(ctx, instanceId, projectId).Execute()
if err != nil {
core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading instance", fmt.Sprintf("Calling API to get alert config: %v", err))
return
}
// Map response body to schema
err = mapFields(ctx, instanceResp, &model)
if err != nil {
core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading instance", fmt.Sprintf("Processing API payload: %v", err))
return
}
err = mapACLField(aclListResp, &model)
if err != nil {
core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading instance", fmt.Sprintf("Processing API response for the ACL: %v", err))
return
}
err = mapAlertConfigField(ctx, alertConfigResp, &model)
if err != nil {
core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating instance", fmt.Sprintf("Processing API response for the alert config: %v", err))
return
}
diags = resp.State.Set(ctx, model)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
tflog.Info(ctx, "Argus instance read")
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,50 +0,0 @@
package argus
const exampleMoveToObservability = "## Example move\n" +
"Example to move the deprecated `stackit_argus_scrapeconfig` resource to the new `stackit_observability_scrapeconfig` resource:" + "\n" +
"1. Add a new `stackit_observability_scrapeconfig` resource with the same values like your previous `stackit_argus_scrapeconfig` resource." + "\n" +
"1. Add a moved block which reference the `stackit_argus_scrapeconfig` and `stackit_observability_scrapeconfig` resource." + "\n" +
"1. Remove your old `stackit_argus_scrapeconfig` resource and run `$ terraform apply`." + "\n" +
"```terraform" +
`
resource "stackit_argus_scrapeconfig" "example" {
project_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
instance_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
name = "example-job"
metrics_path = "/my-metrics"
saml2 = {
enable_url_parameters = true
}
targets = [
{
urls = ["url1", "urls2"]
labels = {
"url1" = "dev"
}
}
]
}
moved {
from = stackit_argus_scrapeconfig.example
to = stackit_observability_scrapeconfig.example
}
resource "stackit_observability_scrapeconfig" "example" {
project_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
instance_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
name = "example-job"
metrics_path = "/my-metrics"
saml2 = {
enable_url_parameters = true
}
targets = [
{
urls = ["url1", "urls2"]
labels = {
"url1" = "dev"
}
}
]
}
` + "```" + "\n"

View file

@ -1,243 +0,0 @@
package argus
import (
"context"
"fmt"
"net/http"
"github.com/hashicorp/terraform-plugin-framework-validators/int64validator"
"github.com/hashicorp/terraform-plugin-framework-validators/listvalidator"
"github.com/hashicorp/terraform-plugin-framework-validators/mapvalidator"
"github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
"github.com/hashicorp/terraform-plugin-framework/datasource"
"github.com/hashicorp/terraform-plugin-framework/datasource/schema"
"github.com/hashicorp/terraform-plugin-framework/schema/validator"
"github.com/hashicorp/terraform-plugin-framework/types"
"github.com/hashicorp/terraform-plugin-log/tflog"
"github.com/stackitcloud/stackit-sdk-go/core/config"
"github.com/stackitcloud/stackit-sdk-go/core/oapierror"
"github.com/stackitcloud/stackit-sdk-go/services/argus"
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/core"
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/validate"
)
// Ensure the implementation satisfies the expected interfaces.
var (
_ datasource.DataSource = &scrapeConfigDataSource{}
)
// NewScrapeConfigDataSource is a helper function to simplify the provider implementation.
func NewScrapeConfigDataSource() datasource.DataSource {
return &scrapeConfigDataSource{}
}
// scrapeConfigDataSource is the data source implementation.
type scrapeConfigDataSource struct {
client *argus.APIClient
}
// Metadata returns the data source type name.
func (d *scrapeConfigDataSource) Metadata(_ context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) {
resp.TypeName = req.ProviderTypeName + "_argus_scrapeconfig"
}
func (d *scrapeConfigDataSource) Configure(ctx context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) {
// Prevent panic if the provider has not been configured.
if req.ProviderData == nil {
return
}
var apiClient *argus.APIClient
var err error
providerData, ok := req.ProviderData.(core.ProviderData)
if !ok {
core.LogAndAddError(ctx, &resp.Diagnostics, "Error configuring API client", fmt.Sprintf("Expected configure type stackit.ProviderData, got %T", req.ProviderData))
return
}
if providerData.ArgusCustomEndpoint != "" {
apiClient, err = argus.NewAPIClient(
config.WithCustomAuth(providerData.RoundTripper),
config.WithEndpoint(providerData.ArgusCustomEndpoint),
)
} else {
apiClient, err = argus.NewAPIClient(
config.WithCustomAuth(providerData.RoundTripper),
config.WithRegion(providerData.GetRegion()),
)
}
if err != nil {
core.LogAndAddError(ctx, &resp.Diagnostics, "Error configuring API client", fmt.Sprintf("Configuring client: %v. This is an error related to the provider configuration, not to the data source configuration", err))
return
}
d.client = apiClient
}
// Schema defines the schema for the data source.
func (d *scrapeConfigDataSource) Schema(_ context.Context, _ datasource.SchemaRequest, resp *datasource.SchemaResponse) {
descriptions := map[string]string{
"main": "Argus scrape config data source schema. Must have a `region` specified in the provider configuration.",
"deprecation_message": "The `stackit_argus_scrapeconfig` data source has been deprecated and will be removed after February 26th 2025. " +
"Please use `stackit_observability_scrapeconfig` instead, which offers the exact same functionality.",
}
resp.Schema = schema.Schema{
Description: fmt.Sprintf("%s\n%s", descriptions["main"], descriptions["deprecation_message"]),
MarkdownDescription: fmt.Sprintf("%s\n\n!> %s", descriptions["main"], descriptions["deprecation_message"]),
DeprecationMessage: descriptions["deprecation_message"],
Attributes: map[string]schema.Attribute{
"id": schema.StringAttribute{
Description: "Terraform's internal data source. ID. It is structured as \"`project_id`,`instance_id`,`name`\".",
Computed: true,
},
"project_id": schema.StringAttribute{
Description: "STACKIT project ID to which the scraping job is associated.",
Required: true,
Validators: []validator.String{
validate.UUID(),
validate.NoSeparator(),
},
},
"instance_id": schema.StringAttribute{
Description: "Argus instance ID to which the scraping job is associated.",
Required: true,
Validators: []validator.String{
validate.UUID(),
validate.NoSeparator(),
},
},
"name": schema.StringAttribute{
Description: "Specifies the name of the scraping job",
Required: true,
Validators: []validator.String{
validate.NoSeparator(),
stringvalidator.LengthBetween(1, 200),
},
},
"metrics_path": schema.StringAttribute{
Description: "Specifies the job scraping url path.",
Computed: true,
},
"scheme": schema.StringAttribute{
Description: "Specifies the http scheme.",
Computed: true,
},
"scrape_interval": schema.StringAttribute{
Description: "Specifies the scrape interval as duration string.",
Validators: []validator.String{
stringvalidator.LengthBetween(2, 8),
},
Computed: true,
},
"sample_limit": schema.Int64Attribute{
Description: "Specifies the scrape sample limit.",
Computed: true,
Validators: []validator.Int64{
int64validator.Between(1, 3000000),
},
},
"scrape_timeout": schema.StringAttribute{
Description: "Specifies the scrape timeout as duration string.",
Computed: true,
},
"saml2": schema.SingleNestedAttribute{
Description: "A SAML2 configuration block.",
Computed: true,
Attributes: map[string]schema.Attribute{
"enable_url_parameters": schema.BoolAttribute{
Description: "Specifies if URL parameters are enabled",
Computed: true,
},
},
},
"basic_auth": schema.SingleNestedAttribute{
Description: "A basic authentication block.",
Computed: true,
Attributes: map[string]schema.Attribute{
"username": schema.StringAttribute{
Description: "Specifies basic auth username.",
Computed: true,
Validators: []validator.String{
stringvalidator.LengthBetween(1, 200),
},
},
"password": schema.StringAttribute{
Description: "Specifies basic auth password.",
Computed: true,
Sensitive: true,
Validators: []validator.String{
stringvalidator.LengthBetween(1, 200),
},
},
},
},
"targets": schema.ListNestedAttribute{
Description: "The targets list (specified by the static config).",
Computed: true,
NestedObject: schema.NestedAttributeObject{
Attributes: map[string]schema.Attribute{
"urls": schema.ListAttribute{
Description: "Specifies target URLs.",
Computed: true,
ElementType: types.StringType,
Validators: []validator.List{
listvalidator.ValueStringsAre(
stringvalidator.LengthBetween(1, 500),
),
},
},
"labels": schema.MapAttribute{
Description: "Specifies labels.",
Computed: true,
ElementType: types.StringType,
Validators: []validator.Map{
mapvalidator.SizeAtMost(10),
mapvalidator.ValueStringsAre(stringvalidator.LengthBetween(0, 200)),
mapvalidator.KeysAre(stringvalidator.LengthBetween(0, 200)),
},
},
},
},
},
},
}
}
// Read refreshes the Terraform state with the latest data.
func (d *scrapeConfigDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { // nolint:gocritic // function signature required by Terraform
var model Model
diags := req.Config.Get(ctx, &model)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
projectId := model.ProjectId.ValueString()
instanceId := model.InstanceId.ValueString()
scName := model.Name.ValueString()
scResp, err := d.client.GetScrapeConfig(ctx, instanceId, scName, projectId).Execute()
if err != nil {
oapiErr, ok := err.(*oapierror.GenericOpenAPIError) //nolint:errorlint //complaining that error.As should be used to catch wrapped errors, but this error should not be wrapped
if ok && oapiErr.StatusCode == http.StatusNotFound {
resp.State.RemoveResource(ctx)
}
core.LogAndAddError(ctx, &resp.Diagnostics, "Unable to read scrape config", err.Error())
return
}
err = mapFields(ctx, scResp.Data, &model)
if err != nil {
core.LogAndAddError(ctx, &resp.Diagnostics, "Mapping fields", err.Error())
return
}
diags = resp.State.Set(ctx, model)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
tflog.Info(ctx, "Argus scrape config read")
}

View file

@ -1,880 +0,0 @@
package argus
import (
"context"
"fmt"
"net/http"
"strings"
"time"
"github.com/hashicorp/terraform-plugin-framework-validators/int64validator"
"github.com/hashicorp/terraform-plugin-framework-validators/listvalidator"
"github.com/hashicorp/terraform-plugin-framework-validators/mapvalidator"
"github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
"github.com/hashicorp/terraform-plugin-framework/attr"
"github.com/hashicorp/terraform-plugin-framework/path"
"github.com/hashicorp/terraform-plugin-framework/resource"
"github.com/hashicorp/terraform-plugin-framework/resource/schema"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/booldefault"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/int64default"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/objectdefault"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/stringdefault"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
"github.com/hashicorp/terraform-plugin-framework/schema/validator"
"github.com/hashicorp/terraform-plugin-framework/types"
"github.com/hashicorp/terraform-plugin-framework/types/basetypes"
"github.com/hashicorp/terraform-plugin-log/tflog"
"github.com/stackitcloud/stackit-sdk-go/core/config"
"github.com/stackitcloud/stackit-sdk-go/core/oapierror"
"github.com/stackitcloud/stackit-sdk-go/core/utils"
"github.com/stackitcloud/stackit-sdk-go/services/argus"
"github.com/stackitcloud/stackit-sdk-go/services/argus/wait"
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/conversion"
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/core"
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/validate"
)
const (
DefaultScheme = "https" // API default is "http"
DefaultScrapeInterval = "5m"
DefaultScrapeTimeout = "2m"
DefaultSampleLimit = int64(5000)
DefaultSAML2EnableURLParameters = true
)
// Ensure the implementation satisfies the expected interfaces.
var (
_ resource.Resource = &scrapeConfigResource{}
_ resource.ResourceWithConfigure = &scrapeConfigResource{}
_ resource.ResourceWithImportState = &scrapeConfigResource{}
)
type Model struct {
Id types.String `tfsdk:"id"` // needed by TF
ProjectId types.String `tfsdk:"project_id"`
InstanceId types.String `tfsdk:"instance_id"`
Name types.String `tfsdk:"name"`
MetricsPath types.String `tfsdk:"metrics_path"`
Scheme types.String `tfsdk:"scheme"`
ScrapeInterval types.String `tfsdk:"scrape_interval"`
ScrapeTimeout types.String `tfsdk:"scrape_timeout"`
SampleLimit types.Int64 `tfsdk:"sample_limit"`
SAML2 types.Object `tfsdk:"saml2"`
BasicAuth types.Object `tfsdk:"basic_auth"`
Targets types.List `tfsdk:"targets"`
}
// Struct corresponding to Model.SAML2
type saml2Model struct {
EnableURLParameters types.Bool `tfsdk:"enable_url_parameters"`
}
// Types corresponding to saml2Model
var saml2Types = map[string]attr.Type{
"enable_url_parameters": types.BoolType,
}
// Struct corresponding to Model.BasicAuth
type basicAuthModel struct {
Username types.String `tfsdk:"username"`
Password types.String `tfsdk:"password"`
}
// Types corresponding to basicAuthModel
var basicAuthTypes = map[string]attr.Type{
"username": types.StringType,
"password": types.StringType,
}
// Struct corresponding to Model.Targets[i]
type targetModel struct {
URLs types.List `tfsdk:"urls"`
Labels types.Map `tfsdk:"labels"`
}
// Types corresponding to targetModel
var targetTypes = map[string]attr.Type{
"urls": types.ListType{ElemType: types.StringType},
"labels": types.MapType{ElemType: types.StringType},
}
// NewScrapeConfigResource is a helper function to simplify the provider implementation.
func NewScrapeConfigResource() resource.Resource {
return &scrapeConfigResource{}
}
// scrapeConfigResource is the resource implementation.
type scrapeConfigResource struct {
client *argus.APIClient
}
// Metadata returns the resource type name.
func (r *scrapeConfigResource) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
resp.TypeName = req.ProviderTypeName + "_argus_scrapeconfig"
}
// Configure adds the provider configured client to the resource.
func (r *scrapeConfigResource) Configure(ctx context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) {
// Prevent panic if the provider has not been configured.
if req.ProviderData == nil {
return
}
providerData, ok := req.ProviderData.(core.ProviderData)
if !ok {
core.LogAndAddError(ctx, &resp.Diagnostics, "Error configuring API client", fmt.Sprintf("Expected configure type stackit.ProviderData, got %T", req.ProviderData))
return
}
var apiClient *argus.APIClient
var err error
if providerData.ArgusCustomEndpoint != "" {
apiClient, err = argus.NewAPIClient(
config.WithCustomAuth(providerData.RoundTripper),
config.WithEndpoint(providerData.ArgusCustomEndpoint),
)
} else {
apiClient, err = argus.NewAPIClient(
config.WithCustomAuth(providerData.RoundTripper),
config.WithRegion(providerData.GetRegion()),
)
}
if err != nil {
core.LogAndAddError(ctx, &resp.Diagnostics, "Error configuring API client", fmt.Sprintf("Configuring client: %v. This is an error related to the provider configuration, not to the resource configuration", err))
return
}
r.client = apiClient
tflog.Info(ctx, "Argus scrape config client configured")
}
var (
descriptions = map[string]string{
"main": "Argus scrape config resource schema. Must have a `region` specified in the provider configuration.",
"deprecation_message": "The `stackit_argus_scrapeconfig` resource has been deprecated and will be removed after February 26th 2025. " +
"Please use `stackit_observability_scrapeconfig` instead, which offers the exact same functionality.",
}
Schema = schema.Schema{
Description: fmt.Sprintf("%s\n%s", descriptions["main"], descriptions["deprecation_message"]),
MarkdownDescription: fmt.Sprintf("%s\n\n!> %s\n\n%s", descriptions["main"], descriptions["deprecation_message"], exampleMoveToObservability),
DeprecationMessage: descriptions["deprecation_message"],
Attributes: map[string]schema.Attribute{
"id": schema.StringAttribute{
Description: "Terraform's internal resource ID. It is structured as \"`project_id`,`instance_id`,`name`\".",
Computed: true,
PlanModifiers: []planmodifier.String{
stringplanmodifier.UseStateForUnknown(),
},
},
"project_id": schema.StringAttribute{
Description: "STACKIT project ID to which the scraping job is associated.",
Required: true,
Validators: []validator.String{
validate.UUID(),
validate.NoSeparator(),
},
PlanModifiers: []planmodifier.String{
stringplanmodifier.RequiresReplace(),
},
},
"instance_id": schema.StringAttribute{
Description: "Argus instance ID to which the scraping job is associated.",
Required: true,
Validators: []validator.String{
validate.UUID(),
validate.NoSeparator(),
},
PlanModifiers: []planmodifier.String{
stringplanmodifier.RequiresReplace(),
},
},
"name": schema.StringAttribute{
Description: "Specifies the name of the scraping job.",
Required: true,
Validators: []validator.String{
validate.NoSeparator(),
stringvalidator.LengthBetween(1, 200),
},
PlanModifiers: []planmodifier.String{
stringplanmodifier.RequiresReplace(),
},
},
"metrics_path": schema.StringAttribute{
Description: "Specifies the job scraping url path. E.g. `/metrics`.",
Required: true,
Validators: []validator.String{
stringvalidator.LengthBetween(1, 200),
},
},
"scheme": schema.StringAttribute{
Description: "Specifies the http scheme. Defaults to `https`.",
Optional: true,
Computed: true,
Default: stringdefault.StaticString(DefaultScheme),
},
"scrape_interval": schema.StringAttribute{
Description: "Specifies the scrape interval as duration string. Defaults to `5m`.",
Optional: true,
Computed: true,
Validators: []validator.String{
stringvalidator.LengthBetween(2, 8),
},
Default: stringdefault.StaticString(DefaultScrapeInterval),
},
"scrape_timeout": schema.StringAttribute{
Description: "Specifies the scrape timeout as duration string. Defaults to `2m`.",
Optional: true,
Computed: true,
Validators: []validator.String{
stringvalidator.LengthBetween(2, 8),
},
Default: stringdefault.StaticString(DefaultScrapeTimeout),
},
"sample_limit": schema.Int64Attribute{
Description: "Specifies the scrape sample limit. Upper limit depends on the service plan. Defaults to `5000`.",
Optional: true,
Computed: true,
Validators: []validator.Int64{
int64validator.Between(1, 3000000),
},
Default: int64default.StaticInt64(DefaultSampleLimit),
},
"saml2": schema.SingleNestedAttribute{
Description: "A SAML2 configuration block.",
Optional: true,
Computed: true,
Default: objectdefault.StaticValue(
types.ObjectValueMust(
map[string]attr.Type{
"enable_url_parameters": types.BoolType,
},
map[string]attr.Value{
"enable_url_parameters": types.BoolValue(DefaultSAML2EnableURLParameters),
},
),
),
Attributes: map[string]schema.Attribute{
"enable_url_parameters": schema.BoolAttribute{
Description: "Specifies if URL parameters are enabled. Defaults to `true`",
Optional: true,
Computed: true,
Default: booldefault.StaticBool(DefaultSAML2EnableURLParameters),
},
},
},
"basic_auth": schema.SingleNestedAttribute{
Description: "A basic authentication block.",
Optional: true,
Computed: true,
Attributes: map[string]schema.Attribute{
"username": schema.StringAttribute{
Description: "Specifies basic auth username.",
Required: true,
Validators: []validator.String{
stringvalidator.LengthBetween(1, 200),
},
},
"password": schema.StringAttribute{
Description: "Specifies basic auth password.",
Required: true,
Sensitive: true,
Validators: []validator.String{
stringvalidator.LengthBetween(1, 200),
},
},
},
},
"targets": schema.ListNestedAttribute{
Description: "The targets list (specified by the static config).",
Required: true,
NestedObject: schema.NestedAttributeObject{
Attributes: map[string]schema.Attribute{
"urls": schema.ListAttribute{
Description: "Specifies target URLs.",
Required: true,
ElementType: types.StringType,
Validators: []validator.List{
listvalidator.ValueStringsAre(
stringvalidator.LengthBetween(1, 500),
),
},
},
"labels": schema.MapAttribute{
Description: "Specifies labels.",
Optional: true,
ElementType: types.StringType,
Validators: []validator.Map{
mapvalidator.SizeAtMost(10),
mapvalidator.ValueStringsAre(stringvalidator.LengthBetween(0, 200)),
mapvalidator.KeysAre(stringvalidator.LengthBetween(0, 200)),
},
},
},
},
},
},
}
)
// Schema defines the schema for the resource.
func (r *scrapeConfigResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) {
resp.Schema = Schema
}
// Create creates the resource and sets the initial Terraform state.
func (r *scrapeConfigResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { // nolint:gocritic // function signature required by Terraform
// Retrieve values from plan
var model Model
diags := req.Plan.Get(ctx, &model)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
projectId := model.ProjectId.ValueString()
instanceId := model.InstanceId.ValueString()
scName := model.Name.ValueString()
saml2Model := saml2Model{}
if !model.SAML2.IsNull() && !model.SAML2.IsUnknown() {
diags = model.SAML2.As(ctx, &saml2Model, basetypes.ObjectAsOptions{})
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
}
basicAuthModel := basicAuthModel{}
if !model.BasicAuth.IsNull() && !model.BasicAuth.IsUnknown() {
diags = model.BasicAuth.As(ctx, &basicAuthModel, basetypes.ObjectAsOptions{})
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
}
targetsModel := []targetModel{}
if !model.Targets.IsNull() && !model.Targets.IsUnknown() {
diags = model.Targets.ElementsAs(ctx, &targetsModel, false)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
}
// Generate API request body from model
payload, err := toCreatePayload(ctx, &model, &saml2Model, &basicAuthModel, targetsModel)
if err != nil {
core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating scrape config", fmt.Sprintf("Creating API payload: %v", err))
return
}
_, err = r.client.CreateScrapeConfig(ctx, instanceId, projectId).CreateScrapeConfigPayload(*payload).Execute()
if err != nil {
core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating scrape config", fmt.Sprintf("Calling API: %v", err))
return
}
_, err = wait.CreateScrapeConfigWaitHandler(ctx, r.client, instanceId, scName, projectId).WaitWithContext(ctx)
if err != nil {
core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating scrape config", fmt.Sprintf("Scrape config creation waiting: %v", err))
return
}
got, err := r.client.GetScrapeConfig(ctx, instanceId, scName, projectId).Execute()
if err != nil {
core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating scrape config", fmt.Sprintf("Calling API for updated data: %v", err))
return
}
err = mapFields(ctx, got.Data, &model)
if err != nil {
core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating scrape config", fmt.Sprintf("Processing API payload: %v", err))
return
}
// Set state to fully populated data
diags = resp.State.Set(ctx, model)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
tflog.Info(ctx, "Argus scrape config created")
}
// Read refreshes the Terraform state with the latest data.
func (r *scrapeConfigResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { // nolint:gocritic // function signature required by Terraform
var model Model
diags := req.State.Get(ctx, &model)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
projectId := model.ProjectId.ValueString()
instanceId := model.InstanceId.ValueString()
scName := model.Name.ValueString()
scResp, err := r.client.GetScrapeConfig(ctx, instanceId, scName, projectId).Execute()
if err != nil {
oapiErr, ok := err.(*oapierror.GenericOpenAPIError) //nolint:errorlint //complaining that error.As should be used to catch wrapped errors, but this error should not be wrapped
if ok && oapiErr.StatusCode == http.StatusNotFound {
resp.State.RemoveResource(ctx)
return
}
core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading scrape config", fmt.Sprintf("Calling API: %v", err))
return
}
// Map response body to schema
err = mapFields(ctx, scResp.Data, &model)
if err != nil {
core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading scrape config", fmt.Sprintf("Processing API payload: %v", err))
return
}
// Set refreshed model
diags = resp.State.Set(ctx, model)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
tflog.Info(ctx, "Argus scrape config read")
}
// Update updates the resource and sets the updated Terraform state on success.
func (r *scrapeConfigResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { // nolint:gocritic // function signature required by Terraform
// Retrieve values from plan
var model Model
diags := req.Plan.Get(ctx, &model)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
projectId := model.ProjectId.ValueString()
instanceId := model.InstanceId.ValueString()
scName := model.Name.ValueString()
saml2Model := saml2Model{}
if !model.SAML2.IsNull() && !model.SAML2.IsUnknown() {
diags = model.SAML2.As(ctx, &saml2Model, basetypes.ObjectAsOptions{})
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
}
basicAuthModel := basicAuthModel{}
if !model.BasicAuth.IsNull() && !model.BasicAuth.IsUnknown() {
diags = model.BasicAuth.As(ctx, &basicAuthModel, basetypes.ObjectAsOptions{})
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
}
targetsModel := []targetModel{}
if !model.Targets.IsNull() && !model.Targets.IsUnknown() {
diags = model.Targets.ElementsAs(ctx, &targetsModel, false)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
}
// Generate API request body from model
payload, err := toUpdatePayload(ctx, &model, &saml2Model, &basicAuthModel, targetsModel)
if err != nil {
core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating scrape config", fmt.Sprintf("Creating API payload: %v", err))
return
}
_, err = r.client.UpdateScrapeConfig(ctx, instanceId, scName, projectId).UpdateScrapeConfigPayload(*payload).Execute()
if err != nil {
core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating scrape config", fmt.Sprintf("Calling API: %v", err))
return
}
// We do not have an update status provided by the argus scrape config api, so we cannot use a waiter here, hence a simple sleep is used.
time.Sleep(15 * time.Second)
// Fetch updated ScrapeConfig
scResp, err := r.client.GetScrapeConfig(ctx, instanceId, scName, projectId).Execute()
if err != nil {
core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating scrape config", fmt.Sprintf("Calling API for updated data: %v", err))
return
}
err = mapFields(ctx, scResp.Data, &model)
if err != nil {
core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating scrape config", fmt.Sprintf("Processing API payload: %v", err))
return
}
diags = resp.State.Set(ctx, model)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
tflog.Info(ctx, "Argus scrape config updated")
}
// Delete deletes the resource and removes the Terraform state on success.
func (r *scrapeConfigResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { // nolint:gocritic // function signature required by Terraform
// Retrieve values from state
var model Model
diags := req.State.Get(ctx, &model)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
projectId := model.ProjectId.ValueString()
instanceId := model.InstanceId.ValueString()
scName := model.Name.ValueString()
// Delete existing ScrapeConfig
_, err := r.client.DeleteScrapeConfig(ctx, instanceId, scName, projectId).Execute()
if err != nil {
core.LogAndAddError(ctx, &resp.Diagnostics, "Error deleting scrape config", fmt.Sprintf("Calling API: %v", err))
return
}
_, err = wait.DeleteScrapeConfigWaitHandler(ctx, r.client, instanceId, scName, projectId).WaitWithContext(ctx)
if err != nil {
core.LogAndAddError(ctx, &resp.Diagnostics, "Error deleting scrape config", fmt.Sprintf("Scrape config deletion waiting: %v", err))
return
}
tflog.Info(ctx, "Argus scrape config deleted")
}
// ImportState imports a resource into the Terraform state on success.
// The expected format of the resource import identifier is: project_id,instance_id,name
func (r *scrapeConfigResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) {
idParts := strings.Split(req.ID, core.Separator)
if len(idParts) != 3 || idParts[0] == "" || idParts[1] == "" || idParts[2] == "" {
core.LogAndAddError(ctx, &resp.Diagnostics,
"Error importing scrape config",
fmt.Sprintf("Expected import identifier with format: [project_id],[instance_id],[name] Got: %q", req.ID),
)
return
}
resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("project_id"), idParts[0])...)
resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("instance_id"), idParts[1])...)
resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("name"), idParts[2])...)
tflog.Info(ctx, "Argus scrape config state imported")
}
func mapFields(ctx context.Context, sc *argus.Job, model *Model) error {
if sc == nil {
return fmt.Errorf("response input is nil")
}
if model == nil {
return fmt.Errorf("model input is nil")
}
var scName string
if model.Name.ValueString() != "" {
scName = model.Name.ValueString()
} else if sc.JobName != nil {
scName = *sc.JobName
} else {
return fmt.Errorf("scrape config name not present")
}
idParts := []string{
model.ProjectId.ValueString(),
model.InstanceId.ValueString(),
scName,
}
model.Id = types.StringValue(
strings.Join(idParts, core.Separator),
)
model.Name = types.StringValue(scName)
model.MetricsPath = types.StringPointerValue(sc.MetricsPath)
model.Scheme = types.StringPointerValue(sc.Scheme)
model.ScrapeInterval = types.StringPointerValue(sc.ScrapeInterval)
model.ScrapeTimeout = types.StringPointerValue(sc.ScrapeTimeout)
model.SampleLimit = types.Int64PointerValue(sc.SampleLimit)
err := mapSAML2(sc, model)
if err != nil {
return fmt.Errorf("map saml2: %w", err)
}
err = mapBasicAuth(sc, model)
if err != nil {
return fmt.Errorf("map basic auth: %w", err)
}
err = mapTargets(ctx, sc, model)
if err != nil {
return fmt.Errorf("map targets: %w", err)
}
return nil
}
func mapBasicAuth(sc *argus.Job, model *Model) error {
if sc.BasicAuth == nil {
model.BasicAuth = types.ObjectNull(basicAuthTypes)
return nil
}
basicAuthMap := map[string]attr.Value{
"username": types.StringValue(*sc.BasicAuth.Username),
"password": types.StringValue(*sc.BasicAuth.Password),
}
basicAuthTF, diags := types.ObjectValue(basicAuthTypes, basicAuthMap)
if diags.HasError() {
return core.DiagsToError(diags)
}
model.BasicAuth = basicAuthTF
return nil
}
func mapSAML2(sc *argus.Job, model *Model) error {
if (sc.Params == nil || *sc.Params == nil) && model.SAML2.IsNull() {
return nil
}
if model.SAML2.IsNull() || model.SAML2.IsUnknown() {
model.SAML2 = types.ObjectNull(saml2Types)
}
flag := true
if sc.Params == nil || *sc.Params == nil {
return nil
}
p := *sc.Params
if v, ok := p["saml2"]; ok {
if len(v) == 1 && v[0] == "disabled" {
flag = false
}
}
saml2Map := map[string]attr.Value{
"enable_url_parameters": types.BoolValue(flag),
}
saml2TF, diags := types.ObjectValue(saml2Types, saml2Map)
if diags.HasError() {
return core.DiagsToError(diags)
}
model.SAML2 = saml2TF
return nil
}
func mapTargets(ctx context.Context, sc *argus.Job, model *Model) error {
if sc == nil || sc.StaticConfigs == nil {
model.Targets = types.ListNull(types.ObjectType{AttrTypes: targetTypes})
return nil
}
targetsModel := []targetModel{}
if !model.Targets.IsNull() && !model.Targets.IsUnknown() {
diags := model.Targets.ElementsAs(ctx, &targetsModel, false)
if diags.HasError() {
return core.DiagsToError(diags)
}
}
newTargets := []attr.Value{}
for i, sc := range *sc.StaticConfigs {
nt := targetModel{}
// Map URLs
urls := []attr.Value{}
if sc.Targets != nil {
for _, v := range *sc.Targets {
urls = append(urls, types.StringValue(v))
}
}
nt.URLs = types.ListValueMust(types.StringType, urls)
// Map Labels
if len(model.Targets.Elements()) > i && targetsModel[i].Labels.IsNull() || sc.Labels == nil {
nt.Labels = types.MapNull(types.StringType)
} else {
newl := map[string]attr.Value{}
for k, v := range *sc.Labels {
newl[k] = types.StringValue(v)
}
nt.Labels = types.MapValueMust(types.StringType, newl)
}
// Build target
targetMap := map[string]attr.Value{
"urls": nt.URLs,
"labels": nt.Labels,
}
targetTF, diags := types.ObjectValue(targetTypes, targetMap)
if diags.HasError() {
return core.DiagsToError(diags)
}
newTargets = append(newTargets, targetTF)
}
targetsTF, diags := types.ListValue(types.ObjectType{AttrTypes: targetTypes}, newTargets)
if diags.HasError() {
return core.DiagsToError(diags)
}
model.Targets = targetsTF
return nil
}
func toCreatePayload(ctx context.Context, model *Model, saml2Model *saml2Model, basicAuthModel *basicAuthModel, targetsModel []targetModel) (*argus.CreateScrapeConfigPayload, error) {
if model == nil {
return nil, fmt.Errorf("nil model")
}
sc := argus.CreateScrapeConfigPayload{
JobName: conversion.StringValueToPointer(model.Name),
MetricsPath: conversion.StringValueToPointer(model.MetricsPath),
ScrapeInterval: conversion.StringValueToPointer(model.ScrapeInterval),
ScrapeTimeout: conversion.StringValueToPointer(model.ScrapeTimeout),
// potentially lossy conversion, depending on the allowed range for sample_limit
SampleLimit: utils.Ptr(float64(model.SampleLimit.ValueInt64())),
Scheme: conversion.StringValueToPointer(model.Scheme),
}
setDefaultsCreateScrapeConfig(&sc, model, saml2Model)
if !saml2Model.EnableURLParameters.IsNull() && !saml2Model.EnableURLParameters.IsUnknown() {
m := make(map[string]interface{})
if sc.Params != nil {
m = *sc.Params
}
if saml2Model.EnableURLParameters.ValueBool() {
m["saml2"] = []string{"enabled"}
} else {
m["saml2"] = []string{"disabled"}
}
sc.Params = &m
}
if sc.BasicAuth == nil && !basicAuthModel.Username.IsNull() && !basicAuthModel.Password.IsNull() {
sc.BasicAuth = &argus.CreateScrapeConfigPayloadBasicAuth{
Username: conversion.StringValueToPointer(basicAuthModel.Username),
Password: conversion.StringValueToPointer(basicAuthModel.Password),
}
}
t := make([]argus.CreateScrapeConfigPayloadStaticConfigsInner, len(targetsModel))
for i, target := range targetsModel {
ti := argus.CreateScrapeConfigPayloadStaticConfigsInner{}
urls := []string{}
diags := target.URLs.ElementsAs(ctx, &urls, false)
if diags.HasError() {
return nil, core.DiagsToError(diags)
}
ti.Targets = &urls
labels := map[string]interface{}{}
for k, v := range target.Labels.Elements() {
labels[k], _ = conversion.ToString(ctx, v)
}
ti.Labels = &labels
t[i] = ti
}
sc.StaticConfigs = &t
return &sc, nil
}
func setDefaultsCreateScrapeConfig(sc *argus.CreateScrapeConfigPayload, model *Model, saml2Model *saml2Model) {
if sc == nil {
return
}
if model.Scheme.IsNull() || model.Scheme.IsUnknown() {
sc.Scheme = utils.Ptr(DefaultScheme)
}
if model.ScrapeInterval.IsNull() || model.ScrapeInterval.IsUnknown() {
sc.ScrapeInterval = utils.Ptr(DefaultScrapeInterval)
}
if model.ScrapeTimeout.IsNull() || model.ScrapeTimeout.IsUnknown() {
sc.ScrapeTimeout = utils.Ptr(DefaultScrapeTimeout)
}
if model.SampleLimit.IsNull() || model.SampleLimit.IsUnknown() {
sc.SampleLimit = utils.Ptr(float64(DefaultSampleLimit))
}
// Make the API default more explicit by setting the field.
if saml2Model.EnableURLParameters.IsNull() || saml2Model.EnableURLParameters.IsUnknown() {
m := map[string]interface{}{}
if sc.Params != nil {
m = *sc.Params
}
if DefaultSAML2EnableURLParameters {
m["saml2"] = []string{"enabled"}
} else {
m["saml2"] = []string{"disabled"}
}
sc.Params = &m
}
}
func toUpdatePayload(ctx context.Context, model *Model, saml2Model *saml2Model, basicAuthModel *basicAuthModel, targetsModel []targetModel) (*argus.UpdateScrapeConfigPayload, error) {
if model == nil {
return nil, fmt.Errorf("nil model")
}
sc := argus.UpdateScrapeConfigPayload{
MetricsPath: conversion.StringValueToPointer(model.MetricsPath),
ScrapeInterval: conversion.StringValueToPointer(model.ScrapeInterval),
ScrapeTimeout: conversion.StringValueToPointer(model.ScrapeTimeout),
// potentially lossy conversion, depending on the allowed range for sample_limit
SampleLimit: utils.Ptr(float64(model.SampleLimit.ValueInt64())),
Scheme: conversion.StringValueToPointer(model.Scheme),
}
setDefaultsUpdateScrapeConfig(&sc, model)
if !saml2Model.EnableURLParameters.IsNull() && !saml2Model.EnableURLParameters.IsUnknown() {
m := make(map[string]interface{})
if sc.Params != nil {
m = *sc.Params
}
if saml2Model.EnableURLParameters.ValueBool() {
m["saml2"] = []string{"enabled"}
} else {
m["saml2"] = []string{"disabled"}
}
sc.Params = &m
}
if sc.BasicAuth == nil && !basicAuthModel.Username.IsNull() && !basicAuthModel.Password.IsNull() {
sc.BasicAuth = &argus.CreateScrapeConfigPayloadBasicAuth{
Username: conversion.StringValueToPointer(basicAuthModel.Username),
Password: conversion.StringValueToPointer(basicAuthModel.Password),
}
}
t := make([]argus.UpdateScrapeConfigPayloadStaticConfigsInner, len(targetsModel))
for i, target := range targetsModel {
ti := argus.UpdateScrapeConfigPayloadStaticConfigsInner{}
urls := []string{}
diags := target.URLs.ElementsAs(ctx, &urls, false)
if diags.HasError() {
return nil, core.DiagsToError(diags)
}
ti.Targets = &urls
ls := map[string]interface{}{}
for k, v := range target.Labels.Elements() {
ls[k], _ = conversion.ToString(ctx, v)
}
ti.Labels = &ls
t[i] = ti
}
sc.StaticConfigs = &t
return &sc, nil
}
func setDefaultsUpdateScrapeConfig(sc *argus.UpdateScrapeConfigPayload, model *Model) {
if sc == nil {
return
}
if model.Scheme.IsNull() || model.Scheme.IsUnknown() {
sc.Scheme = utils.Ptr(DefaultScheme)
}
if model.ScrapeInterval.IsNull() || model.ScrapeInterval.IsUnknown() {
sc.ScrapeInterval = utils.Ptr(DefaultScrapeInterval)
}
if model.ScrapeTimeout.IsNull() || model.ScrapeTimeout.IsUnknown() {
sc.ScrapeTimeout = utils.Ptr(DefaultScrapeTimeout)
}
if model.SampleLimit.IsNull() || model.SampleLimit.IsUnknown() {
sc.SampleLimit = utils.Ptr(float64(DefaultSampleLimit))
}
}

View file

@ -1,504 +0,0 @@
package argus
import (
"context"
"testing"
"github.com/google/go-cmp/cmp"
"github.com/hashicorp/terraform-plugin-framework/attr"
"github.com/hashicorp/terraform-plugin-framework/types"
"github.com/stackitcloud/stackit-sdk-go/core/utils"
"github.com/stackitcloud/stackit-sdk-go/services/argus"
)
func TestMapFields(t *testing.T) {
tests := []struct {
description string
input *argus.Job
expected Model
isValid bool
}{
{
"default_ok",
&argus.Job{
JobName: utils.Ptr("name"),
},
Model{
Id: types.StringValue("pid,iid,name"),
ProjectId: types.StringValue("pid"),
InstanceId: types.StringValue("iid"),
Name: types.StringValue("name"),
MetricsPath: types.StringNull(),
Scheme: types.StringNull(),
ScrapeInterval: types.StringNull(),
ScrapeTimeout: types.StringNull(),
SAML2: types.ObjectNull(saml2Types),
BasicAuth: types.ObjectNull(basicAuthTypes),
Targets: types.ListNull(types.ObjectType{AttrTypes: targetTypes}),
},
true,
},
{
description: "values_ok",
input: &argus.Job{
JobName: utils.Ptr("name"),
MetricsPath: utils.Ptr("/m"),
BasicAuth: &argus.BasicAuth{
Password: utils.Ptr("p"),
Username: utils.Ptr("u"),
},
Params: &map[string][]string{"saml2": {"disabled"}, "x": {"y", "z"}},
Scheme: utils.Ptr("scheme"),
ScrapeInterval: utils.Ptr("1"),
ScrapeTimeout: utils.Ptr("2"),
SampleLimit: utils.Ptr(int64(17)),
StaticConfigs: &[]argus.StaticConfigs{
{
Labels: &map[string]string{"k1": "v1"},
Targets: &[]string{"url1"},
},
{
Labels: &map[string]string{"k2": "v2", "k3": "v3"},
Targets: &[]string{"url1", "url3"},
},
{
Labels: nil,
Targets: &[]string{},
},
},
},
expected: Model{
Id: types.StringValue("pid,iid,name"),
ProjectId: types.StringValue("pid"),
InstanceId: types.StringValue("iid"),
Name: types.StringValue("name"),
MetricsPath: types.StringValue("/m"),
Scheme: types.StringValue("scheme"),
ScrapeInterval: types.StringValue("1"),
ScrapeTimeout: types.StringValue("2"),
SampleLimit: types.Int64Value(17),
SAML2: types.ObjectValueMust(saml2Types, map[string]attr.Value{
"enable_url_parameters": types.BoolValue(false),
}),
BasicAuth: types.ObjectValueMust(basicAuthTypes, map[string]attr.Value{
"username": types.StringValue("u"),
"password": types.StringValue("p"),
}),
Targets: types.ListValueMust(types.ObjectType{AttrTypes: targetTypes}, []attr.Value{
types.ObjectValueMust(targetTypes, map[string]attr.Value{
"urls": types.ListValueMust(types.StringType, []attr.Value{types.StringValue("url1")}),
"labels": types.MapValueMust(types.StringType, map[string]attr.Value{
"k1": types.StringValue("v1"),
}),
}),
types.ObjectValueMust(targetTypes, map[string]attr.Value{
"urls": types.ListValueMust(types.StringType, []attr.Value{types.StringValue("url1"), types.StringValue("url3")}),
"labels": types.MapValueMust(types.StringType, map[string]attr.Value{
"k2": types.StringValue("v2"),
"k3": types.StringValue("v3"),
}),
}),
types.ObjectValueMust(targetTypes, map[string]attr.Value{
"urls": types.ListValueMust(types.StringType, []attr.Value{}),
"labels": types.MapNull(types.StringType),
}),
}),
},
isValid: true,
},
{
"response_nil_fail",
nil,
Model{},
false,
},
{
"no_resource_id",
&argus.Job{},
Model{},
false,
},
}
for _, tt := range tests {
t.Run(tt.description, func(t *testing.T) {
state := &Model{
ProjectId: tt.expected.ProjectId,
InstanceId: tt.expected.InstanceId,
}
err := mapFields(context.Background(), tt.input, state)
if !tt.isValid && err == nil {
t.Fatalf("Should have failed")
}
if tt.isValid && err != nil {
t.Fatalf("Should not have failed: %v", err)
}
if tt.isValid {
diff := cmp.Diff(state, &tt.expected)
if diff != "" {
t.Fatalf("Data does not match: %s", diff)
}
}
})
}
}
func TestToCreatePayload(t *testing.T) {
tests := []struct {
description string
input *Model
inputSAML2 *saml2Model
inputBasicAuth *basicAuthModel
inputTargets []targetModel
expected *argus.CreateScrapeConfigPayload
isValid bool
}{
{
"basic_ok",
&Model{
MetricsPath: types.StringValue("/metrics"),
},
&saml2Model{},
&basicAuthModel{},
[]targetModel{},
&argus.CreateScrapeConfigPayload{
MetricsPath: utils.Ptr("/metrics"),
// Defaults
Scheme: utils.Ptr("https"),
ScrapeInterval: utils.Ptr("5m"),
ScrapeTimeout: utils.Ptr("2m"),
SampleLimit: utils.Ptr(float64(5000)),
StaticConfigs: &[]argus.CreateScrapeConfigPayloadStaticConfigsInner{},
Params: &map[string]any{"saml2": []string{"enabled"}},
},
true,
},
{
"ok - false enable_url_parameters",
&Model{
MetricsPath: types.StringValue("/metrics"),
Name: types.StringValue("Name"),
},
&saml2Model{
EnableURLParameters: types.BoolValue(false),
},
&basicAuthModel{},
[]targetModel{},
&argus.CreateScrapeConfigPayload{
MetricsPath: utils.Ptr("/metrics"),
JobName: utils.Ptr("Name"),
Params: &map[string]any{"saml2": []string{"disabled"}},
// Defaults
Scheme: utils.Ptr("https"),
ScrapeInterval: utils.Ptr("5m"),
ScrapeTimeout: utils.Ptr("2m"),
SampleLimit: utils.Ptr(float64(5000)),
StaticConfigs: &[]argus.CreateScrapeConfigPayloadStaticConfigsInner{},
},
true,
},
{
"ok - true enable_url_parameters",
&Model{
MetricsPath: types.StringValue("/metrics"),
Name: types.StringValue("Name"),
},
&saml2Model{
EnableURLParameters: types.BoolValue(true),
},
&basicAuthModel{},
[]targetModel{},
&argus.CreateScrapeConfigPayload{
MetricsPath: utils.Ptr("/metrics"),
JobName: utils.Ptr("Name"),
Params: &map[string]any{"saml2": []string{"enabled"}},
// Defaults
Scheme: utils.Ptr("https"),
ScrapeInterval: utils.Ptr("5m"),
ScrapeTimeout: utils.Ptr("2m"),
SampleLimit: utils.Ptr(float64(5000)),
StaticConfigs: &[]argus.CreateScrapeConfigPayloadStaticConfigsInner{},
},
true,
},
{
"ok - with basic auth",
&Model{
MetricsPath: types.StringValue("/metrics"),
Name: types.StringValue("Name"),
},
&saml2Model{},
&basicAuthModel{
Username: types.StringValue("u"),
Password: types.StringValue("p"),
},
[]targetModel{},
&argus.CreateScrapeConfigPayload{
MetricsPath: utils.Ptr("/metrics"),
JobName: utils.Ptr("Name"),
BasicAuth: &argus.CreateScrapeConfigPayloadBasicAuth{
Username: utils.Ptr("u"),
Password: utils.Ptr("p"),
},
// Defaults
Scheme: utils.Ptr("https"),
ScrapeInterval: utils.Ptr("5m"),
ScrapeTimeout: utils.Ptr("2m"),
SampleLimit: utils.Ptr(float64(5000)),
StaticConfigs: &[]argus.CreateScrapeConfigPayloadStaticConfigsInner{},
Params: &map[string]any{"saml2": []string{"enabled"}},
},
true,
},
{
"ok - with targets",
&Model{
MetricsPath: types.StringValue("/metrics"),
Name: types.StringValue("Name"),
},
&saml2Model{},
&basicAuthModel{},
[]targetModel{
{
URLs: types.ListValueMust(types.StringType, []attr.Value{types.StringValue("url1")}),
Labels: types.MapValueMust(types.StringType, map[string]attr.Value{"k1": types.StringValue("v1")}),
},
{
URLs: types.ListValueMust(types.StringType, []attr.Value{types.StringValue("url1"), types.StringValue("url3")}),
Labels: types.MapValueMust(types.StringType, map[string]attr.Value{"k2": types.StringValue("v2"), "k3": types.StringValue("v3")}),
},
{
URLs: types.ListValueMust(types.StringType, []attr.Value{}),
Labels: types.MapNull(types.StringType),
},
},
&argus.CreateScrapeConfigPayload{
MetricsPath: utils.Ptr("/metrics"),
JobName: utils.Ptr("Name"),
StaticConfigs: &[]argus.CreateScrapeConfigPayloadStaticConfigsInner{
{
Targets: &[]string{"url1"},
Labels: &map[string]interface{}{"k1": "v1"},
},
{
Targets: &[]string{"url1", "url3"},
Labels: &map[string]interface{}{"k2": "v2", "k3": "v3"},
},
{
Targets: &[]string{},
Labels: &map[string]interface{}{},
},
},
// Defaults
Scheme: utils.Ptr("https"),
ScrapeInterval: utils.Ptr("5m"),
ScrapeTimeout: utils.Ptr("2m"),
SampleLimit: utils.Ptr(float64(5000)),
Params: &map[string]any{"saml2": []string{"enabled"}},
},
true,
},
{
"nil_model",
nil,
nil,
nil,
nil,
nil,
false,
},
}
for _, tt := range tests {
t.Run(tt.description, func(t *testing.T) {
output, err := toCreatePayload(context.Background(), tt.input, tt.inputSAML2, tt.inputBasicAuth, tt.inputTargets)
if !tt.isValid && err == nil {
t.Fatalf("Should have failed")
}
if tt.isValid && err != nil {
t.Fatalf("Should not have failed: %v", err)
}
if tt.isValid {
diff := cmp.Diff(output, tt.expected)
if diff != "" {
t.Fatalf("Data does not match: %s", diff)
}
}
})
}
}
func TestToUpdatePayload(t *testing.T) {
tests := []struct {
description string
input *Model
inputSAML2 *saml2Model
basicAuthModel *basicAuthModel
inputTargets []targetModel
expected *argus.UpdateScrapeConfigPayload
isValid bool
}{
{
"basic_ok",
&Model{
MetricsPath: types.StringValue("/metrics"),
},
&saml2Model{},
&basicAuthModel{},
[]targetModel{},
&argus.UpdateScrapeConfigPayload{
MetricsPath: utils.Ptr("/metrics"),
// Defaults
Scheme: utils.Ptr("https"),
ScrapeInterval: utils.Ptr("5m"),
ScrapeTimeout: utils.Ptr("2m"),
SampleLimit: utils.Ptr(float64(5000)),
StaticConfigs: &[]argus.UpdateScrapeConfigPayloadStaticConfigsInner{},
},
true,
},
{
"ok - true enable_url_parameters",
&Model{
MetricsPath: types.StringValue("/metrics"),
Scheme: types.StringValue("http"),
},
&saml2Model{
EnableURLParameters: types.BoolValue(true),
},
&basicAuthModel{},
[]targetModel{},
&argus.UpdateScrapeConfigPayload{
MetricsPath: utils.Ptr("/metrics"),
// Defaults
Scheme: utils.Ptr("http"),
ScrapeInterval: utils.Ptr("5m"),
ScrapeTimeout: utils.Ptr("2m"),
SampleLimit: utils.Ptr(float64(5000)),
StaticConfigs: &[]argus.UpdateScrapeConfigPayloadStaticConfigsInner{},
Params: &map[string]any{"saml2": []string{"enabled"}},
},
true,
},
{
"ok - false enable_url_parameters",
&Model{
MetricsPath: types.StringValue("/metrics"),
Scheme: types.StringValue("http"),
},
&saml2Model{
EnableURLParameters: types.BoolValue(false),
},
&basicAuthModel{},
[]targetModel{},
&argus.UpdateScrapeConfigPayload{
MetricsPath: utils.Ptr("/metrics"),
// Defaults
Scheme: utils.Ptr("http"),
ScrapeInterval: utils.Ptr("5m"),
ScrapeTimeout: utils.Ptr("2m"),
SampleLimit: utils.Ptr(float64(5000)),
StaticConfigs: &[]argus.UpdateScrapeConfigPayloadStaticConfigsInner{},
Params: &map[string]any{"saml2": []string{"disabled"}},
},
true,
},
{
"ok - with basic auth",
&Model{
MetricsPath: types.StringValue("/metrics"),
Name: types.StringValue("Name"),
},
&saml2Model{},
&basicAuthModel{
Username: types.StringValue("u"),
Password: types.StringValue("p"),
},
[]targetModel{},
&argus.UpdateScrapeConfigPayload{
MetricsPath: utils.Ptr("/metrics"),
BasicAuth: &argus.CreateScrapeConfigPayloadBasicAuth{
Username: utils.Ptr("u"),
Password: utils.Ptr("p"),
},
// Defaults
Scheme: utils.Ptr("https"),
ScrapeInterval: utils.Ptr("5m"),
ScrapeTimeout: utils.Ptr("2m"),
SampleLimit: utils.Ptr(float64(5000)),
StaticConfigs: &[]argus.UpdateScrapeConfigPayloadStaticConfigsInner{},
},
true,
},
{
"ok - with targets",
&Model{
MetricsPath: types.StringValue("/metrics"),
Name: types.StringValue("Name"),
},
&saml2Model{},
&basicAuthModel{},
[]targetModel{
{
URLs: types.ListValueMust(types.StringType, []attr.Value{types.StringValue("url1")}),
Labels: types.MapValueMust(types.StringType, map[string]attr.Value{"k1": types.StringValue("v1")}),
},
{
URLs: types.ListValueMust(types.StringType, []attr.Value{types.StringValue("url1"), types.StringValue("url3")}),
Labels: types.MapValueMust(types.StringType, map[string]attr.Value{"k2": types.StringValue("v2"), "k3": types.StringValue("v3")}),
},
{
URLs: types.ListValueMust(types.StringType, []attr.Value{}),
Labels: types.MapNull(types.StringType),
},
},
&argus.UpdateScrapeConfigPayload{
MetricsPath: utils.Ptr("/metrics"),
StaticConfigs: &[]argus.UpdateScrapeConfigPayloadStaticConfigsInner{
{
Targets: &[]string{"url1"},
Labels: &map[string]interface{}{"k1": "v1"},
},
{
Targets: &[]string{"url1", "url3"},
Labels: &map[string]interface{}{"k2": "v2", "k3": "v3"},
},
{
Targets: &[]string{},
Labels: &map[string]interface{}{},
},
},
// Defaults
Scheme: utils.Ptr("https"),
ScrapeInterval: utils.Ptr("5m"),
ScrapeTimeout: utils.Ptr("2m"),
SampleLimit: utils.Ptr(float64(5000)),
},
true,
},
{
"nil_model",
nil,
nil,
nil,
nil,
nil,
false,
},
}
for _, tt := range tests {
t.Run(tt.description, func(t *testing.T) {
output, err := toUpdatePayload(context.Background(), tt.input, tt.inputSAML2, tt.basicAuthModel, tt.inputTargets)
if !tt.isValid && err == nil {
t.Fatalf("Should have failed")
}
if tt.isValid && err != nil {
t.Fatalf("Should not have failed: %v", err)
}
if tt.isValid {
diff := cmp.Diff(output, tt.expected)
if diff != "" {
t.Fatalf("Data does not match: %s", diff)
}
}
})
}
}

View file

@ -3,6 +3,7 @@ package dns
import ( import (
"context" "context"
"fmt" "fmt"
"net/http"
"github.com/hashicorp/terraform-plugin-framework/datasource" "github.com/hashicorp/terraform-plugin-framework/datasource"
"github.com/hashicorp/terraform-plugin-framework/datasource/schema" "github.com/hashicorp/terraform-plugin-framework/datasource/schema"
@ -13,6 +14,7 @@ import (
"github.com/stackitcloud/stackit-sdk-go/services/dns" "github.com/stackitcloud/stackit-sdk-go/services/dns"
"github.com/stackitcloud/stackit-sdk-go/services/dns/wait" "github.com/stackitcloud/stackit-sdk-go/services/dns/wait"
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/core" "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/core"
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/utils"
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/validate" "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/validate"
) )
@ -161,7 +163,17 @@ func (d *recordSetDataSource) Read(ctx context.Context, req datasource.ReadReque
ctx = tflog.SetField(ctx, "record_set_id", recordSetId) ctx = tflog.SetField(ctx, "record_set_id", recordSetId)
recordSetResp, err := d.client.GetRecordSet(ctx, projectId, zoneId, recordSetId).Execute() recordSetResp, err := d.client.GetRecordSet(ctx, projectId, zoneId, recordSetId).Execute()
if err != nil { if err != nil {
core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading record set", fmt.Sprintf("Calling API: %v", err)) utils.LogError(
ctx,
&resp.Diagnostics,
err,
"Reading record set",
fmt.Sprintf("The record set %q or zone %q does not exist in project %q.", recordSetId, zoneId, projectId),
map[int]string{
http.StatusForbidden: fmt.Sprintf("Project with ID %q not found or forbidden access", projectId),
},
)
resp.State.RemoveResource(ctx)
return return
} }
if recordSetResp != nil && recordSetResp.Rrset.State != nil && *recordSetResp.Rrset.State == wait.DeleteSuccess { if recordSetResp != nil && recordSetResp.Rrset.State != nil && *recordSetResp.Rrset.State == wait.DeleteSuccess {

View file

@ -3,6 +3,7 @@ package dns
import ( import (
"context" "context"
"fmt" "fmt"
"net/http"
"github.com/hashicorp/terraform-plugin-framework/datasource" "github.com/hashicorp/terraform-plugin-framework/datasource"
"github.com/hashicorp/terraform-plugin-framework/datasource/schema" "github.com/hashicorp/terraform-plugin-framework/datasource/schema"
@ -13,6 +14,7 @@ import (
"github.com/stackitcloud/stackit-sdk-go/services/dns" "github.com/stackitcloud/stackit-sdk-go/services/dns"
"github.com/stackitcloud/stackit-sdk-go/services/dns/wait" "github.com/stackitcloud/stackit-sdk-go/services/dns/wait"
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/core" "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/core"
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/utils"
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/validate" "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/validate"
) )
@ -191,7 +193,17 @@ func (d *zoneDataSource) Read(ctx context.Context, req datasource.ReadRequest, r
zoneResp, err := d.client.GetZone(ctx, projectId, zoneId).Execute() zoneResp, err := d.client.GetZone(ctx, projectId, zoneId).Execute()
if err != nil { if err != nil {
core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading zone", fmt.Sprintf("Calling API: %v", err)) utils.LogError(
ctx,
&resp.Diagnostics,
err,
"Reading zone",
fmt.Sprintf("Zone with ID %q does not exist in project %q.", zoneId, projectId),
map[int]string{
http.StatusForbidden: fmt.Sprintf("Project with ID %q not found or forbidden access", projectId),
},
)
resp.State.RemoveResource(ctx)
return return
} }
if zoneResp != nil && zoneResp.Zone.State != nil && *zoneResp.Zone.State == wait.DeleteSuccess { if zoneResp != nil && zoneResp.Zone.State != nil && *zoneResp.Zone.State == wait.DeleteSuccess {

View file

@ -7,6 +7,7 @@ import (
"regexp" "regexp"
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/core" "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/core"
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/utils"
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/validate" "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/validate"
"github.com/hashicorp/terraform-plugin-framework-validators/listvalidator" "github.com/hashicorp/terraform-plugin-framework-validators/listvalidator"
@ -17,7 +18,6 @@ import (
"github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-plugin-framework/types"
"github.com/hashicorp/terraform-plugin-log/tflog" "github.com/hashicorp/terraform-plugin-log/tflog"
"github.com/stackitcloud/stackit-sdk-go/core/config" "github.com/stackitcloud/stackit-sdk-go/core/config"
"github.com/stackitcloud/stackit-sdk-go/core/oapierror"
"github.com/stackitcloud/stackit-sdk-go/services/iaas" "github.com/stackitcloud/stackit-sdk-go/services/iaas"
) )
@ -143,12 +143,17 @@ func (d *affinityGroupDatasource) Read(ctx context.Context, req datasource.ReadR
affinityGroupResp, err := d.client.GetAffinityGroupExecute(ctx, projectId, affinityGroupId) affinityGroupResp, err := d.client.GetAffinityGroupExecute(ctx, projectId, affinityGroupId)
if err != nil { if err != nil {
oapiErr, ok := err.(*oapierror.GenericOpenAPIError) //nolint:errorlint //complaining that error.As should be used to catch wrapped errors, but this error should not be wrapped utils.LogError(
if ok && oapiErr.StatusCode == http.StatusNotFound { ctx,
resp.State.RemoveResource(ctx) &resp.Diagnostics,
return err,
} "Reading affinity group",
core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading affinity group", fmt.Sprintf("Call API: %v", err)) fmt.Sprintf("Affinity group with ID %q does not exist in project %q.", affinityGroupId, projectId),
map[int]string{
http.StatusForbidden: fmt.Sprintf("Project with ID %q not found or forbidden access", projectId),
},
)
resp.State.RemoveResource(ctx)
return return
} }

View file

@ -15,9 +15,9 @@ import (
"github.com/hashicorp/terraform-plugin-framework/types/basetypes" "github.com/hashicorp/terraform-plugin-framework/types/basetypes"
"github.com/hashicorp/terraform-plugin-log/tflog" "github.com/hashicorp/terraform-plugin-log/tflog"
"github.com/stackitcloud/stackit-sdk-go/core/config" "github.com/stackitcloud/stackit-sdk-go/core/config"
"github.com/stackitcloud/stackit-sdk-go/core/oapierror"
"github.com/stackitcloud/stackit-sdk-go/services/iaas" "github.com/stackitcloud/stackit-sdk-go/services/iaas"
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/core" "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/core"
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/utils"
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/validate" "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/validate"
) )
@ -238,12 +238,17 @@ func (r *imageDataSource) Read(ctx context.Context, req datasource.ReadRequest,
imageResp, err := r.client.GetImage(ctx, projectId, imageId).Execute() imageResp, err := r.client.GetImage(ctx, projectId, imageId).Execute()
if err != nil { if err != nil {
oapiErr, ok := err.(*oapierror.GenericOpenAPIError) //nolint:errorlint //complaining that error.As should be used to catch wrapped errors, but this error should not be wrapped utils.LogError(
if ok && oapiErr.StatusCode == http.StatusNotFound { ctx,
resp.State.RemoveResource(ctx) &resp.Diagnostics,
return err,
} "Reading image",
core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading image", fmt.Sprintf("Calling API: %v", err)) fmt.Sprintf("Image with ID %q does not exist in project %q.", imageId, projectId),
map[int]string{
http.StatusForbidden: fmt.Sprintf("Project with ID %q not found or forbidden access", projectId),
},
)
resp.State.RemoveResource(ctx)
return return
} }

View file

@ -2,18 +2,16 @@ package keypair
import ( import (
"context" "context"
"errors"
"fmt" "fmt"
"net/http"
"github.com/hashicorp/terraform-plugin-framework/datasource" "github.com/hashicorp/terraform-plugin-framework/datasource"
"github.com/hashicorp/terraform-plugin-framework/datasource/schema" "github.com/hashicorp/terraform-plugin-framework/datasource/schema"
"github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-plugin-framework/types"
"github.com/hashicorp/terraform-plugin-log/tflog" "github.com/hashicorp/terraform-plugin-log/tflog"
"github.com/stackitcloud/stackit-sdk-go/core/config" "github.com/stackitcloud/stackit-sdk-go/core/config"
"github.com/stackitcloud/stackit-sdk-go/core/oapierror"
"github.com/stackitcloud/stackit-sdk-go/services/iaas" "github.com/stackitcloud/stackit-sdk-go/services/iaas"
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/core" "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/core"
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/utils"
) )
// Ensure the implementation satisfies the expected interfaces. // Ensure the implementation satisfies the expected interfaces.
@ -117,18 +115,15 @@ func (r *keyPairDataSource) Read(ctx context.Context, req datasource.ReadRequest
keypairResp, err := r.client.GetKeyPair(ctx, name).Execute() keypairResp, err := r.client.GetKeyPair(ctx, name).Execute()
if err != nil { if err != nil {
var oapiErr *oapierror.GenericOpenAPIError utils.LogError(
ok := errors.As(err, &oapiErr) ctx,
if ok && oapiErr.StatusCode == http.StatusNotFound { &resp.Diagnostics,
summary := fmt.Sprintf("Key Pair with name %q does not exists", name) err,
description := fmt.Sprintf("Key Pair with name %q cannot be found. A key pair can be added with the resource \"stackit_key_pair\"", name) "Reading key pair",
diags.AddError(summary, description) fmt.Sprintf("Key pair with name %q does not exist.", name),
resp.Diagnostics.Append(diags...) nil,
)
resp.State.RemoveResource(ctx) resp.State.RemoveResource(ctx)
return
}
core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading key pair", fmt.Sprintf("Calling API: %v", err))
return return
} }

View file

@ -15,7 +15,6 @@ import (
"github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-plugin-framework/types"
"github.com/hashicorp/terraform-plugin-log/tflog" "github.com/hashicorp/terraform-plugin-log/tflog"
"github.com/stackitcloud/stackit-sdk-go/core/config" "github.com/stackitcloud/stackit-sdk-go/core/config"
"github.com/stackitcloud/stackit-sdk-go/core/oapierror"
"github.com/stackitcloud/stackit-sdk-go/services/iaas" "github.com/stackitcloud/stackit-sdk-go/services/iaas"
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/core" "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/core"
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/utils" "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/utils"
@ -222,12 +221,17 @@ func (d *networkDataSource) Read(ctx context.Context, req datasource.ReadRequest
networkResp, err := d.client.GetNetwork(ctx, projectId, networkId).Execute() networkResp, err := d.client.GetNetwork(ctx, projectId, networkId).Execute()
if err != nil { if err != nil {
oapiErr, ok := err.(*oapierror.GenericOpenAPIError) //nolint:errorlint //complaining that error.As should be used to catch wrapped errors, but this error should not be wrapped utils.LogError(
if ok && oapiErr.StatusCode == http.StatusNotFound { ctx,
resp.State.RemoveResource(ctx) &resp.Diagnostics,
return err,
} "Reading network",
core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading network", fmt.Sprintf("Calling API: %v", err)) fmt.Sprintf("Network with ID %q does not exist in project %q.", networkId, projectId),
map[int]string{
http.StatusForbidden: fmt.Sprintf("Project with ID %q not found or forbidden access", projectId),
},
)
resp.State.RemoveResource(ctx)
return return
} }

View file

@ -14,9 +14,9 @@ import (
"github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-plugin-framework/types"
"github.com/hashicorp/terraform-plugin-log/tflog" "github.com/hashicorp/terraform-plugin-log/tflog"
"github.com/stackitcloud/stackit-sdk-go/core/config" "github.com/stackitcloud/stackit-sdk-go/core/config"
"github.com/stackitcloud/stackit-sdk-go/core/oapierror"
"github.com/stackitcloud/stackit-sdk-go/services/iaas" "github.com/stackitcloud/stackit-sdk-go/services/iaas"
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/core" "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/core"
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/utils"
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/validate" "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/validate"
) )
@ -196,12 +196,17 @@ func (d *networkAreaDataSource) Read(ctx context.Context, req datasource.ReadReq
networkAreaResp, err := d.client.GetNetworkArea(ctx, organizationId, networkAreaId).Execute() networkAreaResp, err := d.client.GetNetworkArea(ctx, organizationId, networkAreaId).Execute()
if err != nil { if err != nil {
oapiErr, ok := err.(*oapierror.GenericOpenAPIError) //nolint:errorlint //complaining that error.As should be used to catch wrapped errors, but this error should not be wrapped utils.LogError(
if ok && oapiErr.StatusCode == http.StatusNotFound { ctx,
resp.State.RemoveResource(ctx) &resp.Diagnostics,
return err,
} "Reading network area",
core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading network area", fmt.Sprintf("Calling API: %v", err)) fmt.Sprintf("Network area with ID %q does not exist in organization %q.", networkAreaId, organizationId),
map[int]string{
http.StatusForbidden: fmt.Sprintf("Organization with ID %q not found or forbidden access", organizationId),
},
)
resp.State.RemoveResource(ctx)
return return
} }

View file

@ -11,9 +11,9 @@ import (
"github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-plugin-framework/types"
"github.com/hashicorp/terraform-plugin-log/tflog" "github.com/hashicorp/terraform-plugin-log/tflog"
"github.com/stackitcloud/stackit-sdk-go/core/config" "github.com/stackitcloud/stackit-sdk-go/core/config"
"github.com/stackitcloud/stackit-sdk-go/core/oapierror"
"github.com/stackitcloud/stackit-sdk-go/services/iaas" "github.com/stackitcloud/stackit-sdk-go/services/iaas"
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/core" "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/core"
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/utils"
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/validate" "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/validate"
) )
@ -141,12 +141,17 @@ func (d *networkAreaRouteDataSource) Read(ctx context.Context, req datasource.Re
networkAreaRouteResp, err := d.client.GetNetworkAreaRoute(ctx, organizationId, networkAreaId, networkAreaRouteId).Execute() networkAreaRouteResp, err := d.client.GetNetworkAreaRoute(ctx, organizationId, networkAreaId, networkAreaRouteId).Execute()
if err != nil { if err != nil {
oapiErr, ok := err.(*oapierror.GenericOpenAPIError) //nolint:errorlint //complaining that error.As should be used to catch wrapped errors, but this error should not be wrapped utils.LogError(
if ok && oapiErr.StatusCode == http.StatusNotFound { ctx,
resp.State.RemoveResource(ctx) &resp.Diagnostics,
return err,
} "Reading network area route",
core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading network area route", fmt.Sprintf("Calling API: %v", err)) fmt.Sprintf("Network area route with ID %q or network area with ID %q does not exist in organization %q.", networkAreaRouteId, networkAreaId, organizationId),
map[int]string{
http.StatusForbidden: fmt.Sprintf("Organization with ID %q not found or forbidden access", organizationId),
},
)
resp.State.RemoveResource(ctx)
return return
} }

View file

@ -11,7 +11,6 @@ import (
"github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-plugin-framework/types"
"github.com/hashicorp/terraform-plugin-log/tflog" "github.com/hashicorp/terraform-plugin-log/tflog"
"github.com/stackitcloud/stackit-sdk-go/core/config" "github.com/stackitcloud/stackit-sdk-go/core/config"
"github.com/stackitcloud/stackit-sdk-go/core/oapierror"
"github.com/stackitcloud/stackit-sdk-go/services/iaas" "github.com/stackitcloud/stackit-sdk-go/services/iaas"
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/core" "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/core"
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/utils" "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/utils"
@ -170,12 +169,17 @@ func (d *networkInterfaceDataSource) Read(ctx context.Context, req datasource.Re
networkInterfaceResp, err := d.client.GetNic(ctx, projectId, networkId, networkInterfaceId).Execute() networkInterfaceResp, err := d.client.GetNic(ctx, projectId, networkId, networkInterfaceId).Execute()
if err != nil { if err != nil {
oapiErr, ok := err.(*oapierror.GenericOpenAPIError) //nolint:errorlint //complaining that error.As should be used to catch wrapped errors, but this error should not be wrapped utils.LogError(
if ok && oapiErr.StatusCode == http.StatusNotFound { ctx,
resp.State.RemoveResource(ctx) &resp.Diagnostics,
return err,
} "Reading network interface",
core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading network interface", fmt.Sprintf("Calling API: %v", err)) fmt.Sprintf("Network interface with ID %q or network with ID %q does not exist in project %q.", networkInterfaceId, networkId, projectId),
map[int]string{
http.StatusForbidden: fmt.Sprintf("Project with ID %q not found or forbidden access", projectId),
},
)
resp.State.RemoveResource(ctx)
return return
} }

View file

@ -11,9 +11,9 @@ import (
"github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-plugin-framework/types"
"github.com/hashicorp/terraform-plugin-log/tflog" "github.com/hashicorp/terraform-plugin-log/tflog"
"github.com/stackitcloud/stackit-sdk-go/core/config" "github.com/stackitcloud/stackit-sdk-go/core/config"
"github.com/stackitcloud/stackit-sdk-go/core/oapierror"
"github.com/stackitcloud/stackit-sdk-go/services/iaas" "github.com/stackitcloud/stackit-sdk-go/services/iaas"
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/core" "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/core"
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/utils"
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/validate" "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/validate"
) )
@ -135,12 +135,17 @@ func (d *publicIpDataSource) Read(ctx context.Context, req datasource.ReadReques
publicIpResp, err := d.client.GetPublicIP(ctx, projectId, publicIpId).Execute() publicIpResp, err := d.client.GetPublicIP(ctx, projectId, publicIpId).Execute()
if err != nil { if err != nil {
oapiErr, ok := err.(*oapierror.GenericOpenAPIError) //nolint:errorlint //complaining that error.As should be used to catch wrapped errors, but this error should not be wrapped utils.LogError(
if ok && oapiErr.StatusCode == http.StatusNotFound { ctx,
resp.State.RemoveResource(ctx) &resp.Diagnostics,
return err,
} "Reading public ip",
core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading public IP", fmt.Sprintf("Calling API: %v", err)) fmt.Sprintf("Public ip with ID %q does not exist in project %q.", publicIpId, projectId),
map[int]string{
http.StatusForbidden: fmt.Sprintf("Project with ID %q not found or forbidden access", projectId),
},
)
resp.State.RemoveResource(ctx)
return return
} }

View file

@ -9,6 +9,7 @@ import (
"github.com/stackitcloud/stackit-sdk-go/services/iaas" "github.com/stackitcloud/stackit-sdk-go/services/iaas"
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/core" "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/core"
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/utils"
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/validate" "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/validate"
"github.com/hashicorp/terraform-plugin-framework-validators/listvalidator" "github.com/hashicorp/terraform-plugin-framework-validators/listvalidator"
@ -19,7 +20,6 @@ import (
"github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-plugin-framework/types"
"github.com/hashicorp/terraform-plugin-log/tflog" "github.com/hashicorp/terraform-plugin-log/tflog"
"github.com/stackitcloud/stackit-sdk-go/core/config" "github.com/stackitcloud/stackit-sdk-go/core/config"
"github.com/stackitcloud/stackit-sdk-go/core/oapierror"
) )
// Ensure the implementation satisfies the expected interfaces. // Ensure the implementation satisfies the expected interfaces.
@ -130,12 +130,17 @@ func (d *publicIpRangesDataSource) Read(ctx context.Context, req datasource.Read
} }
publicIpRangeResp, err := d.client.ListPublicIPRangesExecute(ctx) publicIpRangeResp, err := d.client.ListPublicIPRangesExecute(ctx)
if err != nil { if err != nil {
oapiErr, ok := err.(*oapierror.GenericOpenAPIError) //nolint:errorlint //complaining that error.As should be used to catch wrapped errors, but this error should not be wrapped utils.LogError(
if ok && oapiErr.StatusCode == http.StatusNotFound { ctx,
resp.State.RemoveResource(ctx) &resp.Diagnostics,
return err,
} "Reading public ip ranges",
core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading public IP ranges", fmt.Sprintf("Calling API: %v", err)) "Public ip ranges cannot be found",
map[int]string{
http.StatusForbidden: "Forbidden access",
},
)
resp.State.RemoveResource(ctx)
return return
} }

View file

@ -11,9 +11,9 @@ import (
"github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-plugin-framework/types"
"github.com/hashicorp/terraform-plugin-log/tflog" "github.com/hashicorp/terraform-plugin-log/tflog"
"github.com/stackitcloud/stackit-sdk-go/core/config" "github.com/stackitcloud/stackit-sdk-go/core/config"
"github.com/stackitcloud/stackit-sdk-go/core/oapierror"
"github.com/stackitcloud/stackit-sdk-go/services/iaas" "github.com/stackitcloud/stackit-sdk-go/services/iaas"
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/core" "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/core"
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/utils"
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/validate" "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/validate"
) )
@ -135,12 +135,17 @@ func (d *securityGroupDataSource) Read(ctx context.Context, req datasource.ReadR
securityGroupResp, err := d.client.GetSecurityGroup(ctx, projectId, securityGroupId).Execute() securityGroupResp, err := d.client.GetSecurityGroup(ctx, projectId, securityGroupId).Execute()
if err != nil { if err != nil {
oapiErr, ok := err.(*oapierror.GenericOpenAPIError) //nolint:errorlint //complaining that error.As should be used to catch wrapped errors, but this error should not be wrapped utils.LogError(
if ok && oapiErr.StatusCode == http.StatusNotFound { ctx,
resp.State.RemoveResource(ctx) &resp.Diagnostics,
return err,
} "Reading security group",
core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading security group", fmt.Sprintf("Calling API: %v", err)) fmt.Sprintf("Security group with ID %q does not exist in project %q.", securityGroupId, projectId),
map[int]string{
http.StatusForbidden: fmt.Sprintf("Project with ID %q not found or forbidden access", projectId),
},
)
resp.State.RemoveResource(ctx)
return return
} }

View file

@ -10,7 +10,6 @@ import (
"github.com/hashicorp/terraform-plugin-framework/schema/validator" "github.com/hashicorp/terraform-plugin-framework/schema/validator"
"github.com/hashicorp/terraform-plugin-log/tflog" "github.com/hashicorp/terraform-plugin-log/tflog"
"github.com/stackitcloud/stackit-sdk-go/core/config" "github.com/stackitcloud/stackit-sdk-go/core/config"
"github.com/stackitcloud/stackit-sdk-go/core/oapierror"
"github.com/stackitcloud/stackit-sdk-go/services/iaas" "github.com/stackitcloud/stackit-sdk-go/services/iaas"
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/core" "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/core"
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/utils" "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/utils"
@ -192,12 +191,17 @@ func (d *securityGroupRuleDataSource) Read(ctx context.Context, req datasource.R
securityGroupRuleResp, err := d.client.GetSecurityGroupRule(ctx, projectId, securityGroupId, securityGroupRuleId).Execute() securityGroupRuleResp, err := d.client.GetSecurityGroupRule(ctx, projectId, securityGroupId, securityGroupRuleId).Execute()
if err != nil { if err != nil {
oapiErr, ok := err.(*oapierror.GenericOpenAPIError) //nolint:errorlint //complaining that error.As should be used to catch wrapped errors, but this error should not be wrapped utils.LogError(
if ok && oapiErr.StatusCode == http.StatusNotFound { ctx,
resp.State.RemoveResource(ctx) &resp.Diagnostics,
return err,
} "Reading security group rule",
core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading security group rule", fmt.Sprintf("Calling API: %v", err)) fmt.Sprintf("Security group rule with ID %q or security group with ID %q does not exist in project %q.", securityGroupRuleId, securityGroupId, projectId),
map[int]string{
http.StatusForbidden: fmt.Sprintf("Project with ID %q not found or forbidden access", projectId),
},
)
resp.State.RemoveResource(ctx)
return return
} }

View file

@ -16,9 +16,9 @@ import (
"github.com/hashicorp/terraform-plugin-framework/types/basetypes" "github.com/hashicorp/terraform-plugin-framework/types/basetypes"
"github.com/hashicorp/terraform-plugin-log/tflog" "github.com/hashicorp/terraform-plugin-log/tflog"
"github.com/stackitcloud/stackit-sdk-go/core/config" "github.com/stackitcloud/stackit-sdk-go/core/config"
"github.com/stackitcloud/stackit-sdk-go/core/oapierror"
"github.com/stackitcloud/stackit-sdk-go/services/iaas" "github.com/stackitcloud/stackit-sdk-go/services/iaas"
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/core" "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/core"
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/utils"
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/validate" "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/validate"
) )
@ -213,12 +213,17 @@ func (r *serverDataSource) Read(ctx context.Context, req datasource.ReadRequest,
serverReq = serverReq.Details(true) serverReq = serverReq.Details(true)
serverResp, err := serverReq.Execute() serverResp, err := serverReq.Execute()
if err != nil { if err != nil {
oapiErr, ok := err.(*oapierror.GenericOpenAPIError) //nolint:errorlint //complaining that error.As should be used to catch wrapped errors, but this error should not be wrapped utils.LogError(
if ok && oapiErr.StatusCode == http.StatusNotFound { ctx,
resp.State.RemoveResource(ctx) &resp.Diagnostics,
return err,
} "Reading server",
core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading server", fmt.Sprintf("Calling API: %v", err)) fmt.Sprintf("Server with ID %q does not exist in project %q.", serverId, projectId),
map[int]string{
http.StatusForbidden: fmt.Sprintf("Project with ID %q not found or forbidden access", projectId),
},
)
resp.State.RemoveResource(ctx)
return return
} }

View file

@ -11,7 +11,6 @@ import (
"github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-plugin-framework/types"
"github.com/hashicorp/terraform-plugin-log/tflog" "github.com/hashicorp/terraform-plugin-log/tflog"
"github.com/stackitcloud/stackit-sdk-go/core/config" "github.com/stackitcloud/stackit-sdk-go/core/config"
"github.com/stackitcloud/stackit-sdk-go/core/oapierror"
"github.com/stackitcloud/stackit-sdk-go/services/iaas" "github.com/stackitcloud/stackit-sdk-go/services/iaas"
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/core" "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/core"
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/utils" "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/utils"
@ -166,12 +165,17 @@ func (d *volumeDataSource) Read(ctx context.Context, req datasource.ReadRequest,
volumeResp, err := d.client.GetVolume(ctx, projectId, volumeId).Execute() volumeResp, err := d.client.GetVolume(ctx, projectId, volumeId).Execute()
if err != nil { if err != nil {
oapiErr, ok := err.(*oapierror.GenericOpenAPIError) //nolint:errorlint //complaining that error.As should be used to catch wrapped errors, but this error should not be wrapped utils.LogError(
if ok && oapiErr.StatusCode == http.StatusNotFound { ctx,
resp.State.RemoveResource(ctx) &resp.Diagnostics,
return err,
} "Reading volume",
core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading volume", fmt.Sprintf("Calling API: %v", err)) fmt.Sprintf("Volume with ID %q does not exist in project %q.", volumeId, projectId),
map[int]string{
http.StatusForbidden: fmt.Sprintf("Project with ID %q not found or forbidden access", projectId),
},
)
resp.State.RemoveResource(ctx)
return return
} }

View file

@ -18,7 +18,6 @@ import (
"github.com/hashicorp/terraform-plugin-framework/datasource/schema" "github.com/hashicorp/terraform-plugin-framework/datasource/schema"
"github.com/stackitcloud/stackit-sdk-go/core/config" "github.com/stackitcloud/stackit-sdk-go/core/config"
"github.com/stackitcloud/stackit-sdk-go/core/oapierror"
"github.com/stackitcloud/stackit-sdk-go/services/loadbalancer" "github.com/stackitcloud/stackit-sdk-go/services/loadbalancer"
) )
@ -336,11 +335,17 @@ func (r *loadBalancerDataSource) Read(ctx context.Context, req datasource.ReadRe
lbResp, err := r.client.GetLoadBalancer(ctx, projectId, region, name).Execute() lbResp, err := r.client.GetLoadBalancer(ctx, projectId, region, name).Execute()
if err != nil { if err != nil {
oapiErr, ok := err.(*oapierror.GenericOpenAPIError) //nolint:errorlint //complaining that error.As should be used to catch wrapped errors, but this error should not be wrapped utils.LogError(
if ok && oapiErr.StatusCode == http.StatusNotFound { ctx,
resp.State.RemoveResource(ctx) &resp.Diagnostics,
} err,
core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading load balancer", fmt.Sprintf("Calling API: %v", err)) "Reading load balancer",
fmt.Sprintf("Load balancer with name %q does not exist in project %q.", name, projectId),
map[int]string{
http.StatusForbidden: fmt.Sprintf("Project with ID %q not found or forbidden access", projectId),
},
)
resp.State.RemoveResource(ctx)
return return
} }

View file

@ -9,11 +9,11 @@ import (
"github.com/hashicorp/terraform-plugin-framework/schema/validator" "github.com/hashicorp/terraform-plugin-framework/schema/validator"
"github.com/hashicorp/terraform-plugin-log/tflog" "github.com/hashicorp/terraform-plugin-log/tflog"
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/core" "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/core"
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/utils"
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/validate" "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/validate"
"github.com/hashicorp/terraform-plugin-framework/datasource/schema" "github.com/hashicorp/terraform-plugin-framework/datasource/schema"
"github.com/stackitcloud/stackit-sdk-go/core/config" "github.com/stackitcloud/stackit-sdk-go/core/config"
"github.com/stackitcloud/stackit-sdk-go/core/oapierror"
"github.com/stackitcloud/stackit-sdk-go/services/logme" "github.com/stackitcloud/stackit-sdk-go/services/logme"
) )
@ -152,11 +152,17 @@ func (r *credentialDataSource) Read(ctx context.Context, req datasource.ReadRequ
recordSetResp, err := r.client.GetCredentials(ctx, projectId, instanceId, credentialId).Execute() recordSetResp, err := r.client.GetCredentials(ctx, projectId, instanceId, credentialId).Execute()
if err != nil { if err != nil {
oapiErr, ok := err.(*oapierror.GenericOpenAPIError) //nolint:errorlint //complaining that error.As should be used to catch wrapped errors, but this error should not be wrapped utils.LogError(
if ok && oapiErr.StatusCode == http.StatusNotFound { ctx,
resp.State.RemoveResource(ctx) &resp.Diagnostics,
} err,
core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading credential", fmt.Sprintf("Calling API: %v", err)) "Reading credential",
fmt.Sprintf("Credential with ID %q or instance with ID %q does not exist in project %q.", credentialId, instanceId, projectId),
map[int]string{
http.StatusForbidden: fmt.Sprintf("Project with ID %q not found or forbidden access", projectId),
},
)
resp.State.RemoveResource(ctx)
return return
} }

View file

@ -10,11 +10,11 @@ import (
"github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-plugin-framework/types"
"github.com/hashicorp/terraform-plugin-log/tflog" "github.com/hashicorp/terraform-plugin-log/tflog"
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/core" "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/core"
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/utils"
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/validate" "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/validate"
"github.com/hashicorp/terraform-plugin-framework/datasource/schema" "github.com/hashicorp/terraform-plugin-framework/datasource/schema"
"github.com/stackitcloud/stackit-sdk-go/core/config" "github.com/stackitcloud/stackit-sdk-go/core/config"
"github.com/stackitcloud/stackit-sdk-go/core/oapierror"
"github.com/stackitcloud/stackit-sdk-go/services/logme" "github.com/stackitcloud/stackit-sdk-go/services/logme"
) )
@ -272,11 +272,18 @@ func (r *instanceDataSource) Read(ctx context.Context, req datasource.ReadReques
instanceResp, err := r.client.GetInstance(ctx, projectId, instanceId).Execute() instanceResp, err := r.client.GetInstance(ctx, projectId, instanceId).Execute()
if err != nil { if err != nil {
oapiErr, ok := err.(*oapierror.GenericOpenAPIError) //nolint:errorlint //complaining that error.As should be used to catch wrapped errors, but this error should not be wrapped utils.LogError(
if ok && (oapiErr.StatusCode == http.StatusNotFound || oapiErr.StatusCode == http.StatusGone) { ctx,
resp.State.RemoveResource(ctx) &resp.Diagnostics,
} err,
core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading instance", fmt.Sprintf("Calling API: %v", err)) "Reading instance",
fmt.Sprintf("Instance with ID %q does not exist in project %q.", instanceId, projectId),
map[int]string{
http.StatusForbidden: fmt.Sprintf("Project with ID %q not found or forbidden access", projectId),
http.StatusGone: fmt.Sprintf("Instance %q is gone.", instanceId),
},
)
resp.State.RemoveResource(ctx)
return return
} }

View file

@ -9,12 +9,12 @@ import (
"github.com/hashicorp/terraform-plugin-framework/schema/validator" "github.com/hashicorp/terraform-plugin-framework/schema/validator"
"github.com/hashicorp/terraform-plugin-log/tflog" "github.com/hashicorp/terraform-plugin-log/tflog"
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/core" "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/core"
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/utils"
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/validate" "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/validate"
"github.com/hashicorp/terraform-plugin-framework/datasource/schema" "github.com/hashicorp/terraform-plugin-framework/datasource/schema"
"github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-plugin-framework/types"
"github.com/stackitcloud/stackit-sdk-go/core/config" "github.com/stackitcloud/stackit-sdk-go/core/config"
"github.com/stackitcloud/stackit-sdk-go/core/oapierror"
"github.com/stackitcloud/stackit-sdk-go/services/mariadb" "github.com/stackitcloud/stackit-sdk-go/services/mariadb"
) )
@ -160,11 +160,17 @@ func (r *credentialDataSource) Read(ctx context.Context, req datasource.ReadRequ
recordSetResp, err := r.client.GetCredentials(ctx, projectId, instanceId, credentialId).Execute() recordSetResp, err := r.client.GetCredentials(ctx, projectId, instanceId, credentialId).Execute()
if err != nil { if err != nil {
oapiErr, ok := err.(*oapierror.GenericOpenAPIError) //nolint:errorlint //complaining that error.As should be used to catch wrapped errors, but this error should not be wrapped utils.LogError(
if ok && oapiErr.StatusCode == http.StatusNotFound { ctx,
resp.State.RemoveResource(ctx) &resp.Diagnostics,
} err,
core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading credential", fmt.Sprintf("Calling API: %v", err)) "Reading credential",
fmt.Sprintf("Credential with ID %q or instance with ID %q does not exist in project %q.", credentialId, instanceId, projectId),
map[int]string{
http.StatusForbidden: fmt.Sprintf("Project with ID %q not found or forbidden access", projectId),
},
)
resp.State.RemoveResource(ctx)
return return
} }

View file

@ -10,11 +10,11 @@ import (
"github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-plugin-framework/types"
"github.com/hashicorp/terraform-plugin-log/tflog" "github.com/hashicorp/terraform-plugin-log/tflog"
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/core" "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/core"
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/utils"
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/validate" "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/validate"
"github.com/hashicorp/terraform-plugin-framework/datasource/schema" "github.com/hashicorp/terraform-plugin-framework/datasource/schema"
"github.com/stackitcloud/stackit-sdk-go/core/config" "github.com/stackitcloud/stackit-sdk-go/core/config"
"github.com/stackitcloud/stackit-sdk-go/core/oapierror"
"github.com/stackitcloud/stackit-sdk-go/services/mariadb" "github.com/stackitcloud/stackit-sdk-go/services/mariadb"
) )
@ -208,11 +208,18 @@ func (r *instanceDataSource) Read(ctx context.Context, req datasource.ReadReques
instanceResp, err := r.client.GetInstance(ctx, projectId, instanceId).Execute() instanceResp, err := r.client.GetInstance(ctx, projectId, instanceId).Execute()
if err != nil { if err != nil {
oapiErr, ok := err.(*oapierror.GenericOpenAPIError) //nolint:errorlint //complaining that error.As should be used to catch wrapped errors, but this error should not be wrapped utils.LogError(
if ok && (oapiErr.StatusCode == http.StatusNotFound || oapiErr.StatusCode == http.StatusGone) { ctx,
resp.State.RemoveResource(ctx) &resp.Diagnostics,
} err,
core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading instance", fmt.Sprintf("Calling API: %v", err)) "Reading instance",
fmt.Sprintf("Instance with ID %q does not exist in project %q.", instanceId, projectId),
map[int]string{
http.StatusForbidden: fmt.Sprintf("Project with ID %q not found or forbidden access", projectId),
http.StatusGone: fmt.Sprintf("Instance %q is gone.", instanceId),
},
)
resp.State.RemoveResource(ctx)
return return
} }

View file

@ -10,12 +10,12 @@ import (
"github.com/hashicorp/terraform-plugin-framework/types/basetypes" "github.com/hashicorp/terraform-plugin-framework/types/basetypes"
"github.com/hashicorp/terraform-plugin-log/tflog" "github.com/hashicorp/terraform-plugin-log/tflog"
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/core" "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/core"
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/utils"
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/validate" "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/validate"
"github.com/hashicorp/terraform-plugin-framework/datasource/schema" "github.com/hashicorp/terraform-plugin-framework/datasource/schema"
"github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-plugin-framework/types"
"github.com/stackitcloud/stackit-sdk-go/core/config" "github.com/stackitcloud/stackit-sdk-go/core/config"
"github.com/stackitcloud/stackit-sdk-go/core/oapierror"
"github.com/stackitcloud/stackit-sdk-go/services/mongodbflex" "github.com/stackitcloud/stackit-sdk-go/services/mongodbflex"
) )
@ -213,11 +213,17 @@ func (r *instanceDataSource) Read(ctx context.Context, req datasource.ReadReques
ctx = tflog.SetField(ctx, "instance_id", instanceId) ctx = tflog.SetField(ctx, "instance_id", instanceId)
instanceResp, err := r.client.GetInstance(ctx, projectId, instanceId).Execute() instanceResp, err := r.client.GetInstance(ctx, projectId, instanceId).Execute()
if err != nil { if err != nil {
oapiErr, ok := err.(*oapierror.GenericOpenAPIError) //nolint:errorlint //complaining that error.As should be used to catch wrapped errors, but this error should not be wrapped utils.LogError(
if ok && oapiErr.StatusCode == http.StatusNotFound { ctx,
resp.State.RemoveResource(ctx) &resp.Diagnostics,
} err,
core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading instance", fmt.Sprintf("Calling API: %v", err)) "Reading instance",
fmt.Sprintf("Instance with ID %q does not exist in project %q.", instanceId, projectId),
map[int]string{
http.StatusForbidden: fmt.Sprintf("Project with ID %q not found or forbidden access", projectId),
},
)
resp.State.RemoveResource(ctx)
return return
} }

View file

@ -11,12 +11,12 @@ import (
"github.com/hashicorp/terraform-plugin-framework/schema/validator" "github.com/hashicorp/terraform-plugin-framework/schema/validator"
"github.com/hashicorp/terraform-plugin-log/tflog" "github.com/hashicorp/terraform-plugin-log/tflog"
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/core" "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/core"
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/utils"
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/validate" "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/validate"
"github.com/hashicorp/terraform-plugin-framework/datasource/schema" "github.com/hashicorp/terraform-plugin-framework/datasource/schema"
"github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-plugin-framework/types"
"github.com/stackitcloud/stackit-sdk-go/core/config" "github.com/stackitcloud/stackit-sdk-go/core/config"
"github.com/stackitcloud/stackit-sdk-go/core/oapierror"
"github.com/stackitcloud/stackit-sdk-go/services/mongodbflex" "github.com/stackitcloud/stackit-sdk-go/services/mongodbflex"
) )
@ -165,11 +165,17 @@ func (r *userDataSource) Read(ctx context.Context, req datasource.ReadRequest, r
recordSetResp, err := r.client.GetUser(ctx, projectId, instanceId, userId).Execute() recordSetResp, err := r.client.GetUser(ctx, projectId, instanceId, userId).Execute()
if err != nil { if err != nil {
oapiErr, ok := err.(*oapierror.GenericOpenAPIError) //nolint:errorlint //complaining that error.As should be used to catch wrapped errors, but this error should not be wrapped utils.LogError(
if ok && oapiErr.StatusCode == http.StatusNotFound { ctx,
resp.State.RemoveResource(ctx) &resp.Diagnostics,
} err,
core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading user", fmt.Sprintf("Calling API: %v", err)) "Reading user",
fmt.Sprintf("User with ID %q or instance with ID %q does not exist in project %q.", userId, instanceId, projectId),
map[int]string{
http.StatusForbidden: fmt.Sprintf("Project with ID %q not found or forbidden access", projectId),
},
)
resp.State.RemoveResource(ctx)
return return
} }

View file

@ -14,7 +14,6 @@ import (
"github.com/hashicorp/terraform-plugin-framework/datasource/schema" "github.com/hashicorp/terraform-plugin-framework/datasource/schema"
"github.com/stackitcloud/stackit-sdk-go/core/config" "github.com/stackitcloud/stackit-sdk-go/core/config"
"github.com/stackitcloud/stackit-sdk-go/core/oapierror"
"github.com/stackitcloud/stackit-sdk-go/services/objectstorage" "github.com/stackitcloud/stackit-sdk-go/services/objectstorage"
) )
@ -147,11 +146,17 @@ func (r *bucketDataSource) Read(ctx context.Context, req datasource.ReadRequest,
bucketResp, err := r.client.GetBucket(ctx, projectId, region, bucketName).Execute() bucketResp, err := r.client.GetBucket(ctx, projectId, region, bucketName).Execute()
if err != nil { if err != nil {
oapiErr, ok := err.(*oapierror.GenericOpenAPIError) //nolint:errorlint //complaining that error.As should be used to catch wrapped errors, but this error should not be wrapped utils.LogError(
if ok && oapiErr.StatusCode == http.StatusNotFound { ctx,
resp.State.RemoveResource(ctx) &resp.Diagnostics,
} err,
core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading bucket", fmt.Sprintf("Calling API: %v", err)) "Reading bucket",
fmt.Sprintf("Bucket with name %q does not exist in project %q.", bucketName, projectId),
map[int]string{
http.StatusForbidden: fmt.Sprintf("Project with ID %q not found or forbidden access", projectId),
},
)
resp.State.RemoveResource(ctx)
return return
} }

View file

@ -15,7 +15,6 @@ import (
"github.com/hashicorp/terraform-plugin-framework/datasource/schema" "github.com/hashicorp/terraform-plugin-framework/datasource/schema"
"github.com/stackitcloud/stackit-sdk-go/core/config" "github.com/stackitcloud/stackit-sdk-go/core/config"
"github.com/stackitcloud/stackit-sdk-go/core/oapierror"
"github.com/stackitcloud/stackit-sdk-go/services/objectstorage" "github.com/stackitcloud/stackit-sdk-go/services/objectstorage"
) )
@ -157,22 +156,27 @@ func (r *credentialDataSource) Read(ctx context.Context, req datasource.ReadRequ
credentialsGroupResp, err := r.client.ListAccessKeys(ctx, projectId, region).CredentialsGroup(credentialsGroupId).Execute() credentialsGroupResp, err := r.client.ListAccessKeys(ctx, projectId, region).CredentialsGroup(credentialsGroupId).Execute()
if err != nil { if err != nil {
oapiErr, ok := err.(*oapierror.GenericOpenAPIError) //nolint:errorlint //complaining that error.As should be used to catch wrapped errors, but this error should not be wrapped utils.LogError(
if ok && oapiErr.StatusCode == http.StatusNotFound { ctx,
resp.State.RemoveResource(ctx) &resp.Diagnostics,
return err,
} "Reading credential",
core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading credentials", fmt.Sprintf("Calling API: %v", err)) fmt.Sprintf("Credential group with ID %q does not exist in project %q.", credentialsGroupId, projectId),
map[int]string{
http.StatusForbidden: fmt.Sprintf("Project with ID %q not found or forbidden access", projectId),
},
)
resp.State.RemoveResource(ctx)
return return
} }
if credentialsGroupResp == nil { if credentialsGroupResp == nil {
core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading credentials", fmt.Sprintf("Response is nil: %v", err)) core.LogAndAddError(ctx, &resp.Diagnostics, "Reading credentials", fmt.Sprintf("Response is nil: %v", err))
return return
} }
credential := findCredential(*credentialsGroupResp, credentialId) credential := findCredential(*credentialsGroupResp, credentialId)
if credential == nil { if credential == nil {
core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading credential", "Credential not found") core.LogAndAddError(ctx, &resp.Diagnostics, "Reading credential", fmt.Sprintf("Credential with ID %q not found in credentials group %q", credentialId, credentialsGroupId))
return return
} }

View file

@ -152,7 +152,7 @@ func (r *credentialsGroupDataSource) Read(ctx context.Context, req datasource.Re
} }
if !found { if !found {
resp.State.RemoveResource(ctx) resp.State.RemoveResource(ctx)
core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading credentials group", "Credentials group not found") core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading credentials group", fmt.Sprintf("Credentials group with ID %q does not exists in project %q", credentialsGroupId, projectId))
return return
} }

View file

@ -15,10 +15,9 @@ import (
"github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-plugin-framework/types"
"github.com/hashicorp/terraform-plugin-log/tflog" "github.com/hashicorp/terraform-plugin-log/tflog"
"github.com/stackitcloud/stackit-sdk-go/core/config" "github.com/stackitcloud/stackit-sdk-go/core/config"
"github.com/stackitcloud/stackit-sdk-go/core/oapierror"
"github.com/stackitcloud/stackit-sdk-go/services/observability" "github.com/stackitcloud/stackit-sdk-go/services/observability"
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/core" "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/core"
argusCredentialResource "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/services/argus/credential" "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/utils"
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/validate" "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/validate"
) )
@ -26,7 +25,6 @@ import (
var ( var (
_ resource.Resource = &credentialResource{} _ resource.Resource = &credentialResource{}
_ resource.ResourceWithConfigure = &credentialResource{} _ resource.ResourceWithConfigure = &credentialResource{}
_ resource.ResourceWithMoveState = &credentialResource{}
) )
type Model struct { type Model struct {
@ -88,40 +86,6 @@ func (r *credentialResource) Configure(ctx context.Context, req resource.Configu
tflog.Info(ctx, "Observability credential client configured") tflog.Info(ctx, "Observability credential client configured")
} }
func (r *credentialResource) MoveState(_ context.Context) []resource.StateMover {
return []resource.StateMover{
{
SourceSchema: &argusCredentialResource.Schema,
StateMover: func(ctx context.Context, req resource.MoveStateRequest, resp *resource.MoveStateResponse) {
if req.SourceTypeName != "stackit_argus_credential" {
return
}
// Checks source provider
if !strings.HasSuffix(req.SourceProviderAddress, "stackitcloud/stackit") {
return
}
var sourceStateData argusCredentialResource.Model
resp.Diagnostics.Append(req.SourceState.Get(ctx, &sourceStateData)...)
if resp.Diagnostics.HasError() {
return
}
targetStateData := Model{
Id: sourceStateData.Id,
ProjectId: sourceStateData.ProjectId,
InstanceId: sourceStateData.InstanceId,
Username: sourceStateData.Username,
Password: sourceStateData.Password,
}
resp.Diagnostics.Append(resp.TargetState.Set(ctx, targetStateData)...)
},
},
}
}
func (r *credentialResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) { func (r *credentialResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) {
resp.Schema = schema.Schema{ resp.Schema = schema.Schema{
Description: "Observability credential resource schema. Must have a `region` specified in the provider configuration.", Description: "Observability credential resource schema. Must have a `region` specified in the provider configuration.",
@ -246,12 +210,17 @@ func (r *credentialResource) Read(ctx context.Context, req resource.ReadRequest,
userName := model.Username.ValueString() userName := model.Username.ValueString()
_, err := r.client.GetCredentials(ctx, instanceId, projectId, userName).Execute() _, err := r.client.GetCredentials(ctx, instanceId, projectId, userName).Execute()
if err != nil { if err != nil {
oapiErr, ok := err.(*oapierror.GenericOpenAPIError) //nolint:errorlint //complaining that error.As should be used to catch wrapped errors, but this error should not be wrapped utils.LogError(
if ok && oapiErr.StatusCode == http.StatusNotFound { ctx,
resp.State.RemoveResource(ctx) &resp.Diagnostics,
return err,
} "Reading credential",
core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading credential", fmt.Sprintf("Calling API: %v", err)) fmt.Sprintf("Credential with username %q or instance with ID %q does not exist in project %q.", userName, instanceId, projectId),
map[int]string{
http.StatusForbidden: fmt.Sprintf("Project with ID %q not found or forbidden access", projectId),
},
)
resp.State.RemoveResource(ctx)
return return
} }
diags = resp.State.Set(ctx, model) diags = resp.State.Set(ctx, model)

View file

@ -12,10 +12,10 @@ import (
"github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-plugin-framework/types"
"github.com/hashicorp/terraform-plugin-log/tflog" "github.com/hashicorp/terraform-plugin-log/tflog"
"github.com/stackitcloud/stackit-sdk-go/core/config" "github.com/stackitcloud/stackit-sdk-go/core/config"
"github.com/stackitcloud/stackit-sdk-go/core/oapierror"
"github.com/stackitcloud/stackit-sdk-go/services/observability" "github.com/stackitcloud/stackit-sdk-go/services/observability"
"github.com/stackitcloud/stackit-sdk-go/services/observability/wait" "github.com/stackitcloud/stackit-sdk-go/services/observability/wait"
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/core" "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/core"
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/utils"
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/validate" "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/validate"
) )
@ -384,11 +384,17 @@ func (d *instanceDataSource) Read(ctx context.Context, req datasource.ReadReques
instanceId := model.InstanceId.ValueString() instanceId := model.InstanceId.ValueString()
instanceResp, err := d.client.GetInstance(ctx, instanceId, projectId).Execute() instanceResp, err := d.client.GetInstance(ctx, instanceId, projectId).Execute()
if err != nil { if err != nil {
oapiErr, ok := err.(*oapierror.GenericOpenAPIError) //nolint:errorlint //complaining that error.As should be used to catch wrapped errors, but this error should not be wrapped utils.LogError(
if ok && oapiErr.StatusCode == http.StatusNotFound { ctx,
resp.State.RemoveResource(ctx) &resp.Diagnostics,
} err,
core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading instance", fmt.Sprintf("Calling API: %v", err)) "Reading instance",
fmt.Sprintf("Instance with ID %q does not exist in project %q.", instanceId, projectId),
map[int]string{
http.StatusForbidden: fmt.Sprintf("Project with ID %q not found or forbidden access", projectId),
},
)
resp.State.RemoveResource(ctx)
return return
} }
if instanceResp != nil && instanceResp.Status != nil && *instanceResp.Status == wait.DeleteSuccess { if instanceResp != nil && instanceResp.Status != nil && *instanceResp.Status == wait.DeleteSuccess {

View file

@ -31,7 +31,6 @@ import (
"github.com/stackitcloud/stackit-sdk-go/services/observability/wait" "github.com/stackitcloud/stackit-sdk-go/services/observability/wait"
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/conversion" "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/conversion"
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/core" "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/core"
argusInstanceResource "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/services/argus/instance"
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/validate" "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/validate"
) )
@ -44,7 +43,6 @@ var (
_ resource.Resource = &instanceResource{} _ resource.Resource = &instanceResource{}
_ resource.ResourceWithConfigure = &instanceResource{} _ resource.ResourceWithConfigure = &instanceResource{}
_ resource.ResourceWithImportState = &instanceResource{} _ resource.ResourceWithImportState = &instanceResource{}
_ resource.ResourceWithMoveState = &instanceResource{}
) )
type Model struct { type Model struct {
@ -377,64 +375,6 @@ func (r *instanceResource) Configure(ctx context.Context, req resource.Configure
tflog.Info(ctx, "Observability instance client configured") tflog.Info(ctx, "Observability instance client configured")
} }
// MoveState moves the state of a `stackit_argus_instance` resource to a `stackit_observability_instance` resource.
func (r *instanceResource) MoveState(_ context.Context) []resource.StateMover {
return []resource.StateMover{
{
SourceSchema: &argusInstanceResource.Schema,
StateMover: func(ctx context.Context, req resource.MoveStateRequest, resp *resource.MoveStateResponse) {
if req.SourceTypeName != "stackit_argus_instance" {
return
}
// Checks source provider
if !strings.HasSuffix(req.SourceProviderAddress, "stackitcloud/stackit") {
return
}
var sourceStateData argusInstanceResource.Model
resp.Diagnostics.Append(req.SourceState.Get(ctx, &sourceStateData)...)
if resp.Diagnostics.HasError() {
return
}
targetStateData := Model{
Id: sourceStateData.Id,
ProjectId: sourceStateData.ProjectId,
InstanceId: sourceStateData.InstanceId,
Name: sourceStateData.Name,
PlanName: sourceStateData.PlanName,
PlanId: sourceStateData.PlanId,
Parameters: sourceStateData.Parameters,
DashboardURL: sourceStateData.DashboardURL,
IsUpdatable: sourceStateData.IsUpdatable,
GrafanaURL: sourceStateData.GrafanaURL,
GrafanaPublicReadAccess: sourceStateData.GrafanaPublicReadAccess,
GrafanaInitialAdminPassword: sourceStateData.GrafanaInitialAdminPassword,
GrafanaInitialAdminUser: sourceStateData.GrafanaInitialAdminUser,
MetricsRetentionDays: sourceStateData.MetricsRetentionDays,
MetricsRetentionDays5mDownsampling: sourceStateData.MetricsRetentionDays5mDownsampling,
MetricsRetentionDays1hDownsampling: sourceStateData.MetricsRetentionDays1hDownsampling,
MetricsURL: sourceStateData.MetricsURL,
MetricsPushURL: sourceStateData.MetricsPushURL,
TargetsURL: sourceStateData.TargetsURL,
AlertingURL: sourceStateData.AlertingURL,
LogsURL: sourceStateData.LogsURL,
LogsPushURL: sourceStateData.LogsPushURL,
JaegerTracesURL: sourceStateData.JaegerTracesURL,
JaegerUIURL: sourceStateData.JaegerUIURL,
OtlpTracesURL: sourceStateData.OtlpTracesURL,
ZipkinSpansURL: sourceStateData.ZipkinSpansURL,
ACL: sourceStateData.ACL,
AlertConfig: sourceStateData.AlertConfig,
}
resp.Diagnostics.Append(resp.TargetState.Set(ctx, targetStateData)...)
},
},
}
}
// Schema defines the schema for the resource. // Schema defines the schema for the resource.
func (r *instanceResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) { func (r *instanceResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) {
resp.Schema = schema.Schema{ resp.Schema = schema.Schema{

View file

@ -15,9 +15,9 @@ import (
"github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-plugin-framework/types"
"github.com/hashicorp/terraform-plugin-log/tflog" "github.com/hashicorp/terraform-plugin-log/tflog"
"github.com/stackitcloud/stackit-sdk-go/core/config" "github.com/stackitcloud/stackit-sdk-go/core/config"
"github.com/stackitcloud/stackit-sdk-go/core/oapierror"
"github.com/stackitcloud/stackit-sdk-go/services/observability" "github.com/stackitcloud/stackit-sdk-go/services/observability"
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/core" "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/core"
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/utils"
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/validate" "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/validate"
) )
@ -214,11 +214,17 @@ func (d *scrapeConfigDataSource) Read(ctx context.Context, req datasource.ReadRe
scResp, err := d.client.GetScrapeConfig(ctx, instanceId, scName, projectId).Execute() scResp, err := d.client.GetScrapeConfig(ctx, instanceId, scName, projectId).Execute()
if err != nil { if err != nil {
oapiErr, ok := err.(*oapierror.GenericOpenAPIError) //nolint:errorlint //complaining that error.As should be used to catch wrapped errors, but this error should not be wrapped utils.LogError(
if ok && oapiErr.StatusCode == http.StatusNotFound { ctx,
resp.State.RemoveResource(ctx) &resp.Diagnostics,
} err,
core.LogAndAddError(ctx, &resp.Diagnostics, "Unable to read scrape config", err.Error()) "Reading scrape config",
fmt.Sprintf("Scrape config with name %q or instance with ID %q does not exist in project %q.", scName, instanceId, projectId),
map[int]string{
http.StatusForbidden: fmt.Sprintf("Project with ID %q not found or forbidden access", projectId),
},
)
resp.State.RemoveResource(ctx)
return return
} }

View file

@ -32,7 +32,6 @@ import (
"github.com/stackitcloud/stackit-sdk-go/services/observability/wait" "github.com/stackitcloud/stackit-sdk-go/services/observability/wait"
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/conversion" "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/conversion"
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/core" "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/core"
argusScrapeConfigResource "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/services/argus/scrapeconfig"
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/validate" "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/validate"
) )
@ -49,7 +48,6 @@ var (
_ resource.Resource = &scrapeConfigResource{} _ resource.Resource = &scrapeConfigResource{}
_ resource.ResourceWithConfigure = &scrapeConfigResource{} _ resource.ResourceWithConfigure = &scrapeConfigResource{}
_ resource.ResourceWithImportState = &scrapeConfigResource{} _ resource.ResourceWithImportState = &scrapeConfigResource{}
_ resource.ResourceWithMoveState = &scrapeConfigResource{}
) )
type Model struct { type Model struct {
@ -151,47 +149,6 @@ func (r *scrapeConfigResource) Configure(ctx context.Context, req resource.Confi
tflog.Info(ctx, "Observability scrape config client configured") tflog.Info(ctx, "Observability scrape config client configured")
} }
func (r *scrapeConfigResource) MoveState(_ context.Context) []resource.StateMover {
return []resource.StateMover{
{
SourceSchema: &argusScrapeConfigResource.Schema,
StateMover: func(ctx context.Context, req resource.MoveStateRequest, resp *resource.MoveStateResponse) {
if req.SourceTypeName != "stackit_argus_scrapeconfig" {
return
}
// Checks source provider
if !strings.HasSuffix(req.SourceProviderAddress, "stackitcloud/stackit") {
return
}
var sourceStateData argusScrapeConfigResource.Model
resp.Diagnostics.Append(req.SourceState.Get(ctx, &sourceStateData)...)
if resp.Diagnostics.HasError() {
return
}
targetStateData := Model{
Id: sourceStateData.Id,
ProjectId: sourceStateData.ProjectId,
InstanceId: sourceStateData.InstanceId,
Name: sourceStateData.Name,
MetricsPath: sourceStateData.MetricsPath,
Scheme: sourceStateData.Scheme,
ScrapeInterval: sourceStateData.ScrapeInterval,
ScrapeTimeout: sourceStateData.ScrapeTimeout,
SampleLimit: sourceStateData.SampleLimit,
SAML2: sourceStateData.SAML2,
BasicAuth: sourceStateData.BasicAuth,
Targets: sourceStateData.Targets,
}
resp.Diagnostics.Append(resp.TargetState.Set(ctx, targetStateData)...)
},
},
}
}
// Schema defines the schema for the resource. // Schema defines the schema for the resource.
func (r *scrapeConfigResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) { func (r *scrapeConfigResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) {
resp.Schema = schema.Schema{ resp.Schema = schema.Schema{

View file

@ -9,12 +9,12 @@ import (
"github.com/hashicorp/terraform-plugin-framework/schema/validator" "github.com/hashicorp/terraform-plugin-framework/schema/validator"
"github.com/hashicorp/terraform-plugin-log/tflog" "github.com/hashicorp/terraform-plugin-log/tflog"
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/core" "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/core"
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/utils"
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/validate" "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/validate"
"github.com/hashicorp/terraform-plugin-framework/datasource/schema" "github.com/hashicorp/terraform-plugin-framework/datasource/schema"
"github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-plugin-framework/types"
"github.com/stackitcloud/stackit-sdk-go/core/config" "github.com/stackitcloud/stackit-sdk-go/core/config"
"github.com/stackitcloud/stackit-sdk-go/core/oapierror"
"github.com/stackitcloud/stackit-sdk-go/services/opensearch" "github.com/stackitcloud/stackit-sdk-go/services/opensearch"
) )
@ -160,11 +160,17 @@ func (r *credentialDataSource) Read(ctx context.Context, req datasource.ReadRequ
recordSetResp, err := r.client.GetCredentials(ctx, projectId, instanceId, credentialId).Execute() recordSetResp, err := r.client.GetCredentials(ctx, projectId, instanceId, credentialId).Execute()
if err != nil { if err != nil {
oapiErr, ok := err.(*oapierror.GenericOpenAPIError) //nolint:errorlint //complaining that error.As should be used to catch wrapped errors, but this error should not be wrapped utils.LogError(
if ok && oapiErr.StatusCode == http.StatusNotFound { ctx,
resp.State.RemoveResource(ctx) &resp.Diagnostics,
} err,
core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading credential", fmt.Sprintf("Calling API: %v", err)) "Reading credential",
fmt.Sprintf("Credential with ID %q or instance with ID %q does not exist in project %q.", credentialId, instanceId, projectId),
map[int]string{
http.StatusForbidden: fmt.Sprintf("Project with ID %q not found or forbidden access", projectId),
},
)
resp.State.RemoveResource(ctx)
return return
} }

View file

@ -10,11 +10,11 @@ import (
"github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-plugin-framework/types"
"github.com/hashicorp/terraform-plugin-log/tflog" "github.com/hashicorp/terraform-plugin-log/tflog"
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/core" "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/core"
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/utils"
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/validate" "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/validate"
"github.com/hashicorp/terraform-plugin-framework/datasource/schema" "github.com/hashicorp/terraform-plugin-framework/datasource/schema"
"github.com/stackitcloud/stackit-sdk-go/core/config" "github.com/stackitcloud/stackit-sdk-go/core/config"
"github.com/stackitcloud/stackit-sdk-go/core/oapierror"
"github.com/stackitcloud/stackit-sdk-go/services/opensearch" "github.com/stackitcloud/stackit-sdk-go/services/opensearch"
) )
@ -241,11 +241,18 @@ func (r *instanceDataSource) Read(ctx context.Context, req datasource.ReadReques
instanceResp, err := r.client.GetInstance(ctx, projectId, instanceId).Execute() instanceResp, err := r.client.GetInstance(ctx, projectId, instanceId).Execute()
if err != nil { if err != nil {
oapiErr, ok := err.(*oapierror.GenericOpenAPIError) //nolint:errorlint //complaining that error.As should be used to catch wrapped errors, but this error should not be wrapped utils.LogError(
if ok && (oapiErr.StatusCode == http.StatusNotFound || oapiErr.StatusCode == http.StatusGone) { ctx,
resp.State.RemoveResource(ctx) &resp.Diagnostics,
} err,
core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading instance", fmt.Sprintf("Calling API: %v", err)) "Reading instance",
fmt.Sprintf("Instance with ID %q does not exist in project %q.", instanceId, projectId),
map[int]string{
http.StatusForbidden: fmt.Sprintf("Project with ID %q not found or forbidden access", projectId),
http.StatusGone: fmt.Sprintf("Instance %q is gone.", instanceId),
},
)
resp.State.RemoveResource(ctx)
return return
} }

View file

@ -14,7 +14,6 @@ import (
"github.com/hashicorp/terraform-plugin-framework/datasource/schema" "github.com/hashicorp/terraform-plugin-framework/datasource/schema"
"github.com/stackitcloud/stackit-sdk-go/core/config" "github.com/stackitcloud/stackit-sdk-go/core/config"
"github.com/stackitcloud/stackit-sdk-go/core/oapierror"
"github.com/stackitcloud/stackit-sdk-go/services/postgresflex" "github.com/stackitcloud/stackit-sdk-go/services/postgresflex"
) )
@ -160,11 +159,17 @@ func (r *databaseDataSource) Read(ctx context.Context, req datasource.ReadReques
databaseResp, err := getDatabase(ctx, r.client, projectId, region, instanceId, databaseId) databaseResp, err := getDatabase(ctx, r.client, projectId, region, instanceId, databaseId)
if err != nil { if err != nil {
oapiErr, ok := err.(*oapierror.GenericOpenAPIError) //nolint:errorlint //complaining that error.As should be used to catch wrapped errors, but this error should not be wrapped utils.LogError(
if ok && oapiErr.StatusCode == http.StatusNotFound { ctx,
resp.State.RemoveResource(ctx) &resp.Diagnostics,
} err,
core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading database", fmt.Sprintf("Calling API: %v", err)) "Reading database",
fmt.Sprintf("Database with ID %q or instance with ID %q does not exist in project %q.", databaseId, instanceId, projectId),
map[int]string{
http.StatusForbidden: fmt.Sprintf("Project with ID %q not found or forbidden access", projectId),
},
)
resp.State.RemoveResource(ctx)
return return
} }

View file

@ -16,7 +16,6 @@ import (
"github.com/hashicorp/terraform-plugin-framework/datasource/schema" "github.com/hashicorp/terraform-plugin-framework/datasource/schema"
"github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-plugin-framework/types"
"github.com/stackitcloud/stackit-sdk-go/core/config" "github.com/stackitcloud/stackit-sdk-go/core/config"
"github.com/stackitcloud/stackit-sdk-go/core/oapierror"
"github.com/stackitcloud/stackit-sdk-go/services/postgresflex" "github.com/stackitcloud/stackit-sdk-go/services/postgresflex"
"github.com/stackitcloud/stackit-sdk-go/services/postgresflex/wait" "github.com/stackitcloud/stackit-sdk-go/services/postgresflex/wait"
) )
@ -191,11 +190,17 @@ func (r *instanceDataSource) Read(ctx context.Context, req datasource.ReadReques
ctx = tflog.SetField(ctx, "region", region) ctx = tflog.SetField(ctx, "region", region)
instanceResp, err := r.client.GetInstance(ctx, projectId, region, instanceId).Execute() instanceResp, err := r.client.GetInstance(ctx, projectId, region, instanceId).Execute()
if err != nil { if err != nil {
oapiErr, ok := err.(*oapierror.GenericOpenAPIError) //nolint:errorlint //complaining that error.As should be used to catch wrapped errors, but this error should not be wrapped utils.LogError(
if ok && oapiErr.StatusCode == http.StatusNotFound { ctx,
resp.State.RemoveResource(ctx) &resp.Diagnostics,
} err,
core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading instance", fmt.Sprintf("Calling API: %v", err)) "Reading instance",
fmt.Sprintf("Instance with ID %q does not exist in project %q.", instanceId, projectId),
map[int]string{
http.StatusForbidden: fmt.Sprintf("Project with ID %q not found or forbidden access", projectId),
},
)
resp.State.RemoveResource(ctx)
return return
} }
if instanceResp != nil && instanceResp.Item != nil && instanceResp.Item.Status != nil && *instanceResp.Item.Status == wait.InstanceStateDeleted { if instanceResp != nil && instanceResp.Item != nil && instanceResp.Item.Status != nil && *instanceResp.Item.Status == wait.InstanceStateDeleted {

View file

@ -17,7 +17,6 @@ import (
"github.com/hashicorp/terraform-plugin-framework/datasource/schema" "github.com/hashicorp/terraform-plugin-framework/datasource/schema"
"github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-plugin-framework/types"
"github.com/stackitcloud/stackit-sdk-go/core/config" "github.com/stackitcloud/stackit-sdk-go/core/config"
"github.com/stackitcloud/stackit-sdk-go/core/oapierror"
"github.com/stackitcloud/stackit-sdk-go/services/postgresflex" "github.com/stackitcloud/stackit-sdk-go/services/postgresflex"
) )
@ -178,11 +177,17 @@ func (r *userDataSource) Read(ctx context.Context, req datasource.ReadRequest, r
recordSetResp, err := r.client.GetUser(ctx, projectId, region, instanceId, userId).Execute() recordSetResp, err := r.client.GetUser(ctx, projectId, region, instanceId, userId).Execute()
if err != nil { if err != nil {
oapiErr, ok := err.(*oapierror.GenericOpenAPIError) //nolint:errorlint //complaining that error.As should be used to catch wrapped errors, but this error should not be wrapped utils.LogError(
if ok && oapiErr.StatusCode == http.StatusNotFound { ctx,
resp.State.RemoveResource(ctx) &resp.Diagnostics,
} err,
core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading user", fmt.Sprintf("Calling API: %v", err)) "Reading user",
fmt.Sprintf("User with ID %q or instance with ID %q does not exist in project %q.", userId, instanceId, projectId),
map[int]string{
http.StatusForbidden: fmt.Sprintf("Project with ID %q not found or forbidden access", projectId),
},
)
resp.State.RemoveResource(ctx)
return return
} }

View file

@ -9,12 +9,12 @@ import (
"github.com/hashicorp/terraform-plugin-framework/schema/validator" "github.com/hashicorp/terraform-plugin-framework/schema/validator"
"github.com/hashicorp/terraform-plugin-log/tflog" "github.com/hashicorp/terraform-plugin-log/tflog"
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/core" "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/core"
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/utils"
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/validate" "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/validate"
"github.com/hashicorp/terraform-plugin-framework/datasource/schema" "github.com/hashicorp/terraform-plugin-framework/datasource/schema"
"github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-plugin-framework/types"
"github.com/stackitcloud/stackit-sdk-go/core/config" "github.com/stackitcloud/stackit-sdk-go/core/config"
"github.com/stackitcloud/stackit-sdk-go/core/oapierror"
"github.com/stackitcloud/stackit-sdk-go/services/rabbitmq" "github.com/stackitcloud/stackit-sdk-go/services/rabbitmq"
) )
@ -171,11 +171,17 @@ func (r *credentialDataSource) Read(ctx context.Context, req datasource.ReadRequ
recordSetResp, err := r.client.GetCredentials(ctx, projectId, instanceId, credentialId).Execute() recordSetResp, err := r.client.GetCredentials(ctx, projectId, instanceId, credentialId).Execute()
if err != nil { if err != nil {
oapiErr, ok := err.(*oapierror.GenericOpenAPIError) //nolint:errorlint //complaining that error.As should be used to catch wrapped errors, but this error should not be wrapped utils.LogError(
if ok && oapiErr.StatusCode == http.StatusNotFound { ctx,
resp.State.RemoveResource(ctx) &resp.Diagnostics,
} err,
core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading credential", fmt.Sprintf("Calling API: %v", err)) "Reading credential",
fmt.Sprintf("Credential with ID %q or instance with ID %q does not exist in project %q.", credentialId, instanceId, projectId),
map[int]string{
http.StatusForbidden: fmt.Sprintf("Project with ID %q not found or forbidden access", projectId),
},
)
resp.State.RemoveResource(ctx)
return return
} }

View file

@ -10,11 +10,11 @@ import (
"github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-plugin-framework/types"
"github.com/hashicorp/terraform-plugin-log/tflog" "github.com/hashicorp/terraform-plugin-log/tflog"
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/core" "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/core"
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/utils"
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/validate" "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/validate"
"github.com/hashicorp/terraform-plugin-framework/datasource/schema" "github.com/hashicorp/terraform-plugin-framework/datasource/schema"
"github.com/stackitcloud/stackit-sdk-go/core/config" "github.com/stackitcloud/stackit-sdk-go/core/config"
"github.com/stackitcloud/stackit-sdk-go/core/oapierror"
"github.com/stackitcloud/stackit-sdk-go/services/rabbitmq" "github.com/stackitcloud/stackit-sdk-go/services/rabbitmq"
) )
@ -237,11 +237,17 @@ func (r *instanceDataSource) Read(ctx context.Context, req datasource.ReadReques
instanceResp, err := r.client.GetInstance(ctx, projectId, instanceId).Execute() instanceResp, err := r.client.GetInstance(ctx, projectId, instanceId).Execute()
if err != nil { if err != nil {
oapiErr, ok := err.(*oapierror.GenericOpenAPIError) //nolint:errorlint //complaining that error.As should be used to catch wrapped errors, but this error should not be wrapped utils.LogError(
if ok && (oapiErr.StatusCode == http.StatusNotFound || oapiErr.StatusCode == http.StatusGone) { ctx,
resp.State.RemoveResource(ctx) &resp.Diagnostics,
} err,
core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading instance", fmt.Sprintf("Calling API: %v", err)) "Reading instance",
fmt.Sprintf("Instance with ID %q does not exist in project %q.", instanceId, projectId),
map[int]string{
http.StatusForbidden: fmt.Sprintf("Project with ID %q not found or forbidden access", projectId),
},
)
resp.State.RemoveResource(ctx)
return return
} }

View file

@ -9,12 +9,12 @@ import (
"github.com/hashicorp/terraform-plugin-framework/schema/validator" "github.com/hashicorp/terraform-plugin-framework/schema/validator"
"github.com/hashicorp/terraform-plugin-log/tflog" "github.com/hashicorp/terraform-plugin-log/tflog"
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/core" "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/core"
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/utils"
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/validate" "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/validate"
"github.com/hashicorp/terraform-plugin-framework/datasource/schema" "github.com/hashicorp/terraform-plugin-framework/datasource/schema"
"github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-plugin-framework/types"
"github.com/stackitcloud/stackit-sdk-go/core/config" "github.com/stackitcloud/stackit-sdk-go/core/config"
"github.com/stackitcloud/stackit-sdk-go/core/oapierror"
"github.com/stackitcloud/stackit-sdk-go/services/redis" "github.com/stackitcloud/stackit-sdk-go/services/redis"
) )
@ -162,11 +162,17 @@ func (r *credentialDataSource) Read(ctx context.Context, req datasource.ReadRequ
recordSetResp, err := r.client.GetCredentials(ctx, projectId, instanceId, credentialId).Execute() recordSetResp, err := r.client.GetCredentials(ctx, projectId, instanceId, credentialId).Execute()
if err != nil { if err != nil {
oapiErr, ok := err.(*oapierror.GenericOpenAPIError) //nolint:errorlint //complaining that error.As should be used to catch wrapped errors, but this error should not be wrapped utils.LogError(
if ok && oapiErr.StatusCode == http.StatusNotFound { ctx,
resp.State.RemoveResource(ctx) &resp.Diagnostics,
} err,
core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading credential", fmt.Sprintf("Calling API: %v", err)) "Reading credential",
fmt.Sprintf("Credential with ID %q or instance with ID %q does not exist in project %q.", credentialId, instanceId, projectId),
map[int]string{
http.StatusForbidden: fmt.Sprintf("Project with ID %q not found or forbidden access", projectId),
},
)
resp.State.RemoveResource(ctx)
return return
} }

View file

@ -10,11 +10,11 @@ import (
"github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-plugin-framework/types"
"github.com/hashicorp/terraform-plugin-log/tflog" "github.com/hashicorp/terraform-plugin-log/tflog"
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/core" "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/core"
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/utils"
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/validate" "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/validate"
"github.com/hashicorp/terraform-plugin-framework/datasource/schema" "github.com/hashicorp/terraform-plugin-framework/datasource/schema"
"github.com/stackitcloud/stackit-sdk-go/core/config" "github.com/stackitcloud/stackit-sdk-go/core/config"
"github.com/stackitcloud/stackit-sdk-go/core/oapierror"
"github.com/stackitcloud/stackit-sdk-go/services/redis" "github.com/stackitcloud/stackit-sdk-go/services/redis"
) )
@ -285,11 +285,18 @@ func (r *instanceDataSource) Read(ctx context.Context, req datasource.ReadReques
instanceResp, err := r.client.GetInstance(ctx, projectId, instanceId).Execute() instanceResp, err := r.client.GetInstance(ctx, projectId, instanceId).Execute()
if err != nil { if err != nil {
oapiErr, ok := err.(*oapierror.GenericOpenAPIError) //nolint:errorlint //complaining that error.As should be used to catch wrapped errors, but this error should not be wrapped utils.LogError(
if ok && (oapiErr.StatusCode == http.StatusNotFound || oapiErr.StatusCode == http.StatusGone) { ctx,
resp.State.RemoveResource(ctx) &resp.Diagnostics,
} err,
core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading instance", fmt.Sprintf("Calling API: %v", err)) "Reading instance",
fmt.Sprintf("Instance with ID %q does not exist in project %q.", instanceId, projectId),
map[int]string{
http.StatusForbidden: fmt.Sprintf("Project with ID %q not found or forbidden access", projectId),
http.StatusGone: fmt.Sprintf("Instance %q is gone.", instanceId),
},
)
resp.State.RemoveResource(ctx)
return return
} }

View file

@ -11,13 +11,13 @@ import (
"github.com/hashicorp/terraform-plugin-framework/schema/validator" "github.com/hashicorp/terraform-plugin-framework/schema/validator"
"github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-plugin-framework/types"
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/core" "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/core"
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/utils"
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/validate" "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/validate"
"github.com/hashicorp/terraform-plugin-framework/datasource" "github.com/hashicorp/terraform-plugin-framework/datasource"
"github.com/hashicorp/terraform-plugin-framework/datasource/schema" "github.com/hashicorp/terraform-plugin-framework/datasource/schema"
"github.com/hashicorp/terraform-plugin-log/tflog" "github.com/hashicorp/terraform-plugin-log/tflog"
"github.com/stackitcloud/stackit-sdk-go/core/config" "github.com/stackitcloud/stackit-sdk-go/core/config"
"github.com/stackitcloud/stackit-sdk-go/core/oapierror"
"github.com/stackitcloud/stackit-sdk-go/services/resourcemanager" "github.com/stackitcloud/stackit-sdk-go/services/resourcemanager"
) )
@ -165,17 +165,25 @@ func (d *projectDataSource) Read(ctx context.Context, req datasource.ReadRequest
// set project identifier. If projectId is provided, it takes precedence over containerId // set project identifier. If projectId is provided, it takes precedence over containerId
var identifier = containerId var identifier = containerId
identifierType := "Container"
if projectId != "" { if projectId != "" {
identifier = projectId identifier = projectId
identifierType = "Project"
} }
projectResp, err := d.client.GetProject(ctx, identifier).Execute() projectResp, err := d.client.GetProject(ctx, identifier).Execute()
if err != nil { if err != nil {
oapiErr, ok := err.(*oapierror.GenericOpenAPIError) //nolint:errorlint //complaining that error.As should be used to catch wrapped errors, but this error should not be wrapped utils.LogError(
if ok && oapiErr.StatusCode == http.StatusForbidden { ctx,
resp.State.RemoveResource(ctx) &resp.Diagnostics,
} err,
core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading project", fmt.Sprintf("Calling API: %v", err)) "Reading project",
fmt.Sprintf("%s with ID %q does not exist.", identifierType, identifier),
map[int]string{
http.StatusForbidden: fmt.Sprintf("%s with ID %q not found or forbidden access", identifierType, identifier),
},
)
resp.State.RemoveResource(ctx)
return return
} }

View file

@ -10,11 +10,11 @@ import (
"github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-plugin-framework/types"
"github.com/hashicorp/terraform-plugin-log/tflog" "github.com/hashicorp/terraform-plugin-log/tflog"
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/core" "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/core"
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/utils"
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/validate" "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/validate"
"github.com/hashicorp/terraform-plugin-framework/datasource/schema" "github.com/hashicorp/terraform-plugin-framework/datasource/schema"
"github.com/stackitcloud/stackit-sdk-go/core/config" "github.com/stackitcloud/stackit-sdk-go/core/config"
"github.com/stackitcloud/stackit-sdk-go/core/oapierror"
"github.com/stackitcloud/stackit-sdk-go/services/secretsmanager" "github.com/stackitcloud/stackit-sdk-go/services/secretsmanager"
) )
@ -136,11 +136,17 @@ func (r *instanceDataSource) Read(ctx context.Context, req datasource.ReadReques
instanceResp, err := r.client.GetInstance(ctx, projectId, instanceId).Execute() instanceResp, err := r.client.GetInstance(ctx, projectId, instanceId).Execute()
if err != nil { if err != nil {
oapiErr, ok := err.(*oapierror.GenericOpenAPIError) //nolint:errorlint //complaining that error.As should be used to catch wrapped errors, but this error should not be wrapped utils.LogError(
if ok && oapiErr.StatusCode == http.StatusNotFound { ctx,
resp.State.RemoveResource(ctx) &resp.Diagnostics,
} err,
core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading instance", fmt.Sprintf("Calling API: %v", err)) "Reading instance",
fmt.Sprintf("Instance with ID %q does not exist in project %q.", instanceId, projectId),
map[int]string{
http.StatusForbidden: fmt.Sprintf("Project with ID %q not found or forbidden access", projectId),
},
)
resp.State.RemoveResource(ctx)
return return
} }
aclList, err := r.client.ListACLs(ctx, projectId, instanceId).Execute() aclList, err := r.client.ListACLs(ctx, projectId, instanceId).Execute()

View file

@ -10,12 +10,12 @@ import (
"github.com/hashicorp/terraform-plugin-framework/schema/validator" "github.com/hashicorp/terraform-plugin-framework/schema/validator"
"github.com/hashicorp/terraform-plugin-log/tflog" "github.com/hashicorp/terraform-plugin-log/tflog"
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/core" "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/core"
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/utils"
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/validate" "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/validate"
"github.com/hashicorp/terraform-plugin-framework/datasource/schema" "github.com/hashicorp/terraform-plugin-framework/datasource/schema"
"github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-plugin-framework/types"
"github.com/stackitcloud/stackit-sdk-go/core/config" "github.com/stackitcloud/stackit-sdk-go/core/config"
"github.com/stackitcloud/stackit-sdk-go/core/oapierror"
"github.com/stackitcloud/stackit-sdk-go/services/secretsmanager" "github.com/stackitcloud/stackit-sdk-go/services/secretsmanager"
) )
@ -162,11 +162,17 @@ func (r *userDataSource) Read(ctx context.Context, req datasource.ReadRequest, r
userResp, err := r.client.GetUser(ctx, projectId, instanceId, userId).Execute() userResp, err := r.client.GetUser(ctx, projectId, instanceId, userId).Execute()
if err != nil { if err != nil {
oapiErr, ok := err.(*oapierror.GenericOpenAPIError) //nolint:errorlint //complaining that error.As should be used to catch wrapped errors, but this error should not be wrapped utils.LogError(
if ok && oapiErr.StatusCode == http.StatusNotFound { ctx,
resp.State.RemoveResource(ctx) &resp.Diagnostics,
} err,
core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading user", fmt.Sprintf("Calling API: %v", err)) "Reading user",
fmt.Sprintf("User with ID %q or instance with ID %q does not exist in project %q.", userId, instanceId, projectId),
map[int]string{
http.StatusForbidden: fmt.Sprintf("Project with ID %q not found or forbidden access", projectId),
},
)
resp.State.RemoveResource(ctx)
return return
} }

View file

@ -18,7 +18,6 @@ import (
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/validate" "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/validate"
"github.com/stackitcloud/stackit-sdk-go/core/config" "github.com/stackitcloud/stackit-sdk-go/core/config"
"github.com/stackitcloud/stackit-sdk-go/core/oapierror"
"github.com/stackitcloud/stackit-sdk-go/services/serverbackup" "github.com/stackitcloud/stackit-sdk-go/services/serverbackup"
) )
@ -185,11 +184,17 @@ func (r *scheduleDataSource) Read(ctx context.Context, req datasource.ReadReques
scheduleResp, err := r.client.GetBackupSchedule(ctx, projectId, serverId, region, strconv.FormatInt(backupScheduleId, 10)).Execute() scheduleResp, err := r.client.GetBackupSchedule(ctx, projectId, serverId, region, strconv.FormatInt(backupScheduleId, 10)).Execute()
if err != nil { if err != nil {
oapiErr, ok := err.(*oapierror.GenericOpenAPIError) //nolint:errorlint //complaining that error.As should be used to catch wrapped errors, but this error should not be wrapped utils.LogError(
if ok && oapiErr.StatusCode == http.StatusNotFound { ctx,
resp.State.RemoveResource(ctx) &resp.Diagnostics,
} err,
core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading server backup schedule", fmt.Sprintf("Calling API: %v", err)) "Reading server backup schedule",
fmt.Sprintf("Backup schedule with ID %q or server with ID %q does not exist in project %q.", strconv.FormatInt(backupScheduleId, 10), serverId, projectId),
map[int]string{
http.StatusForbidden: fmt.Sprintf("Project with ID %q not found or forbidden access", projectId),
},
)
resp.State.RemoveResource(ctx)
return return
} }

View file

@ -17,7 +17,6 @@ import (
"github.com/hashicorp/terraform-plugin-framework/datasource/schema" "github.com/hashicorp/terraform-plugin-framework/datasource/schema"
"github.com/stackitcloud/stackit-sdk-go/core/config" "github.com/stackitcloud/stackit-sdk-go/core/config"
"github.com/stackitcloud/stackit-sdk-go/core/oapierror"
"github.com/stackitcloud/stackit-sdk-go/services/serverbackup" "github.com/stackitcloud/stackit-sdk-go/services/serverbackup"
) )
@ -205,11 +204,17 @@ func (r *schedulesDataSource) Read(ctx context.Context, req datasource.ReadReque
schedules, err := r.client.ListBackupSchedules(ctx, projectId, serverId, region).Execute() schedules, err := r.client.ListBackupSchedules(ctx, projectId, serverId, region).Execute()
if err != nil { if err != nil {
oapiErr, ok := err.(*oapierror.GenericOpenAPIError) //nolint:errorlint //complaining that error.As should be used to catch wrapped errors, but this error should not be wrapped utils.LogError(
if ok && oapiErr.StatusCode == http.StatusNotFound { ctx,
resp.State.RemoveResource(ctx) &resp.Diagnostics,
} err,
core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading server backup schedules", fmt.Sprintf("Calling API: %v", err)) "Reading server backup schedules",
fmt.Sprintf("Server with ID %q does not exist in project %q.", serverId, projectId),
map[int]string{
http.StatusForbidden: fmt.Sprintf("Project with ID %q not found or forbidden access", projectId),
},
)
resp.State.RemoveResource(ctx)
return return
} }

View file

@ -17,7 +17,6 @@ import (
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/validate" "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/validate"
"github.com/stackitcloud/stackit-sdk-go/core/config" "github.com/stackitcloud/stackit-sdk-go/core/config"
"github.com/stackitcloud/stackit-sdk-go/core/oapierror"
"github.com/stackitcloud/stackit-sdk-go/services/serverupdate" "github.com/stackitcloud/stackit-sdk-go/services/serverupdate"
) )
@ -171,11 +170,17 @@ func (r *scheduleDataSource) Read(ctx context.Context, req datasource.ReadReques
scheduleResp, err := r.client.GetUpdateSchedule(ctx, projectId, serverId, strconv.FormatInt(updateScheduleId, 10), region).Execute() scheduleResp, err := r.client.GetUpdateSchedule(ctx, projectId, serverId, strconv.FormatInt(updateScheduleId, 10), region).Execute()
if err != nil { if err != nil {
oapiErr, ok := err.(*oapierror.GenericOpenAPIError) //nolint:errorlint //complaining that error.As should be used to catch wrapped errors, but this error should not be wrapped utils.LogError(
if ok && oapiErr.StatusCode == http.StatusNotFound { ctx,
resp.State.RemoveResource(ctx) &resp.Diagnostics,
} err,
core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading server update schedule", fmt.Sprintf("Calling API: %v", err)) "Reading server update schedule",
fmt.Sprintf("Update schedule with ID %q or server with ID %q does not exist in project %q.", strconv.FormatInt(updateScheduleId, 10), serverId, projectId),
map[int]string{
http.StatusForbidden: fmt.Sprintf("Project with ID %q not found or forbidden access", projectId),
},
)
resp.State.RemoveResource(ctx)
return return
} }

View file

@ -17,7 +17,6 @@ import (
"github.com/hashicorp/terraform-plugin-framework/datasource/schema" "github.com/hashicorp/terraform-plugin-framework/datasource/schema"
"github.com/stackitcloud/stackit-sdk-go/core/config" "github.com/stackitcloud/stackit-sdk-go/core/config"
"github.com/stackitcloud/stackit-sdk-go/core/oapierror"
"github.com/stackitcloud/stackit-sdk-go/services/serverupdate" "github.com/stackitcloud/stackit-sdk-go/services/serverupdate"
) )
@ -192,11 +191,17 @@ func (r *schedulesDataSource) Read(ctx context.Context, req datasource.ReadReque
schedules, err := r.client.ListUpdateSchedules(ctx, projectId, serverId, region).Execute() schedules, err := r.client.ListUpdateSchedules(ctx, projectId, serverId, region).Execute()
if err != nil { if err != nil {
oapiErr, ok := err.(*oapierror.GenericOpenAPIError) //nolint:errorlint //complaining that error.As should be used to catch wrapped errors, but this error should not be wrapped utils.LogError(
if ok && oapiErr.StatusCode == http.StatusNotFound { ctx,
resp.State.RemoveResource(ctx) &resp.Diagnostics,
} err,
core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading server update schedules", fmt.Sprintf("Calling API: %v", err)) "Reading server update schedules",
fmt.Sprintf("Server with ID %q does not exist in project %q.", serverId, projectId),
map[int]string{
http.StatusForbidden: fmt.Sprintf("Project with ID %q not found or forbidden access", projectId),
},
)
resp.State.RemoveResource(ctx)
return return
} }

View file

@ -13,6 +13,7 @@ import (
"github.com/stackitcloud/stackit-sdk-go/services/serviceaccount" "github.com/stackitcloud/stackit-sdk-go/services/serviceaccount"
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/core" "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/core"
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/features" "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/features"
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/utils"
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/validate" "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/validate"
) )
@ -139,7 +140,15 @@ func (r *serviceAccountDataSource) Read(ctx context.Context, req datasource.Read
// Call the API to list service accounts in the specified project // Call the API to list service accounts in the specified project
listSaResp, err := r.client.ListServiceAccounts(ctx, projectId).Execute() listSaResp, err := r.client.ListServiceAccounts(ctx, projectId).Execute()
if err != nil { if err != nil {
core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading service account", fmt.Sprintf("Error calling API: %v", err)) utils.LogError(
ctx,
&resp.Diagnostics,
err,
"Reading service account",
fmt.Sprintf("Forbidden access for service account in project %q.", projectId),
map[int]string{},
)
resp.State.RemoveResource(ctx)
return return
} }
@ -171,6 +180,6 @@ func (r *serviceAccountDataSource) Read(ctx context.Context, req datasource.Read
} }
// If no matching service account is found, remove the resource from the state // If no matching service account is found, remove the resource from the state
core.LogAndAddError(ctx, &resp.Diagnostics, "Service account not found", "") core.LogAndAddError(ctx, &resp.Diagnostics, "Reading service account", "Service account not found")
resp.State.RemoveResource(ctx) resp.State.RemoveResource(ctx)
} }

View file

@ -11,7 +11,6 @@ import (
"github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-plugin-framework/types"
"github.com/hashicorp/terraform-plugin-log/tflog" "github.com/hashicorp/terraform-plugin-log/tflog"
"github.com/stackitcloud/stackit-sdk-go/core/config" "github.com/stackitcloud/stackit-sdk-go/core/config"
"github.com/stackitcloud/stackit-sdk-go/core/oapierror"
"github.com/stackitcloud/stackit-sdk-go/services/ske" "github.com/stackitcloud/stackit-sdk-go/services/ske"
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/core" "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/core"
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/utils" "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/utils"
@ -353,11 +352,17 @@ func (r *clusterDataSource) Read(ctx context.Context, req datasource.ReadRequest
ctx = tflog.SetField(ctx, "region", region) ctx = tflog.SetField(ctx, "region", region)
clusterResp, err := r.client.GetCluster(ctx, projectId, name).Execute() clusterResp, err := r.client.GetCluster(ctx, projectId, name).Execute()
if err != nil { if err != nil {
oapiErr, ok := err.(*oapierror.GenericOpenAPIError) //nolint:errorlint //complaining that error.As should be used to catch wrapped errors, but this error should not be wrapped utils.LogError(
if ok && oapiErr.StatusCode == http.StatusNotFound { ctx,
resp.State.RemoveResource(ctx) &resp.Diagnostics,
} err,
core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading cluster", fmt.Sprintf("Calling API: %v", err)) "Reading cluster",
fmt.Sprintf("Cluster with name %q does not exist in project %q.", name, projectId),
map[int]string{
http.StatusForbidden: fmt.Sprintf("Project with ID %q not found or forbidden access", projectId),
},
)
resp.State.RemoveResource(ctx)
return return
} }

View file

@ -13,6 +13,7 @@ import (
"github.com/hashicorp/terraform-plugin-log/tflog" "github.com/hashicorp/terraform-plugin-log/tflog"
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/conversion" "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/conversion"
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/core" "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/core"
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/utils"
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/validate" "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/validate"
"github.com/hashicorp/terraform-plugin-framework/resource" "github.com/hashicorp/terraform-plugin-framework/resource"
@ -24,8 +25,7 @@ import (
"github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier" "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
"github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-plugin-framework/types"
"github.com/stackitcloud/stackit-sdk-go/core/config" "github.com/stackitcloud/stackit-sdk-go/core/config"
"github.com/stackitcloud/stackit-sdk-go/core/oapierror" sdkUtils "github.com/stackitcloud/stackit-sdk-go/core/utils"
"github.com/stackitcloud/stackit-sdk-go/core/utils"
"github.com/stackitcloud/stackit-sdk-go/services/ske" "github.com/stackitcloud/stackit-sdk-go/services/ske"
) )
@ -261,12 +261,17 @@ func (r *kubeconfigResource) Read(ctx context.Context, req resource.ReadRequest,
cluster, err := r.client.GetClusterExecute(ctx, projectId, clusterName) cluster, err := r.client.GetClusterExecute(ctx, projectId, clusterName)
if err != nil { if err != nil {
oapiErr, ok := err.(*oapierror.GenericOpenAPIError) //nolint:errorlint //complaining that error.As should be used to catch wrapped errors, but this error should not be wrapped utils.LogError(
if ok && oapiErr.StatusCode == http.StatusNotFound { ctx,
resp.State.RemoveResource(ctx) &resp.Diagnostics,
return err,
} "Reading kubeconfig",
core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading kubeconfig", fmt.Sprintf("Could not get cluster(%s): %v", clusterName, err)) fmt.Sprintf("Kubeconfig with ID %q or cluster with name %q does not exist in project %q.", kubeconfigUUID, clusterName, projectId),
map[int]string{
http.StatusForbidden: fmt.Sprintf("Project with ID %q not found or forbidden access", projectId),
},
)
resp.State.RemoveResource(ctx)
return return
} }
@ -391,7 +396,7 @@ func toCreatePayload(model *Model) (*ske.CreateKubeconfigPayload, error) {
expiration := conversion.Int64ValueToPointer(model.Expiration) expiration := conversion.Int64ValueToPointer(model.Expiration)
var expirationStringPtr *string var expirationStringPtr *string
if expiration != nil { if expiration != nil {
expirationStringPtr = utils.Ptr(strconv.FormatInt(*expiration, 10)) expirationStringPtr = sdkUtils.Ptr(strconv.FormatInt(*expiration, 10))
} }
return &ske.CreateKubeconfigPayload{ return &ske.CreateKubeconfigPayload{

View file

@ -16,7 +16,6 @@ import (
"github.com/hashicorp/terraform-plugin-framework/datasource/schema" "github.com/hashicorp/terraform-plugin-framework/datasource/schema"
"github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-plugin-framework/types"
"github.com/stackitcloud/stackit-sdk-go/core/config" "github.com/stackitcloud/stackit-sdk-go/core/config"
"github.com/stackitcloud/stackit-sdk-go/core/oapierror"
"github.com/stackitcloud/stackit-sdk-go/services/sqlserverflex" "github.com/stackitcloud/stackit-sdk-go/services/sqlserverflex"
) )
@ -205,11 +204,17 @@ func (r *instanceDataSource) Read(ctx context.Context, req datasource.ReadReques
ctx = tflog.SetField(ctx, "region", region) ctx = tflog.SetField(ctx, "region", region)
instanceResp, err := r.client.GetInstance(ctx, projectId, instanceId, region).Execute() instanceResp, err := r.client.GetInstance(ctx, projectId, instanceId, region).Execute()
if err != nil { if err != nil {
oapiErr, ok := err.(*oapierror.GenericOpenAPIError) //nolint:errorlint //complaining that error.As should be used to catch wrapped errors, but this error should not be wrapped utils.LogError(
if ok && oapiErr.StatusCode == http.StatusNotFound { ctx,
resp.State.RemoveResource(ctx) &resp.Diagnostics,
} err,
core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading instance", fmt.Sprintf("Calling API: %v", err)) "Reading instance",
fmt.Sprintf("Instance with ID %q does not exist in project %q.", instanceId, projectId),
map[int]string{
http.StatusForbidden: fmt.Sprintf("Project with ID %q not found or forbidden access", projectId),
},
)
resp.State.RemoveResource(ctx)
return return
} }

View file

@ -17,7 +17,6 @@ import (
"github.com/hashicorp/terraform-plugin-framework/datasource/schema" "github.com/hashicorp/terraform-plugin-framework/datasource/schema"
"github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-plugin-framework/types"
"github.com/stackitcloud/stackit-sdk-go/core/config" "github.com/stackitcloud/stackit-sdk-go/core/config"
"github.com/stackitcloud/stackit-sdk-go/core/oapierror"
"github.com/stackitcloud/stackit-sdk-go/services/sqlserverflex" "github.com/stackitcloud/stackit-sdk-go/services/sqlserverflex"
) )
@ -183,11 +182,17 @@ func (r *userDataSource) Read(ctx context.Context, req datasource.ReadRequest, r
recordSetResp, err := r.client.GetUser(ctx, projectId, instanceId, userId, region).Execute() recordSetResp, err := r.client.GetUser(ctx, projectId, instanceId, userId, region).Execute()
if err != nil { if err != nil {
oapiErr, ok := err.(*oapierror.GenericOpenAPIError) //nolint:errorlint //complaining that error.As should be used to catch wrapped errors, but this error should not be wrapped utils.LogError(
if ok && oapiErr.StatusCode == http.StatusNotFound { ctx,
resp.State.RemoveResource(ctx) &resp.Diagnostics,
} err,
core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading user", fmt.Sprintf("Calling API: %v", err)) "Reading user",
fmt.Sprintf("User with ID %q or instance with ID %q does not exist in project %q.", userId, instanceId, projectId),
map[int]string{
http.StatusForbidden: fmt.Sprintf("Project with ID %q not found or forbidden access", projectId),
},
)
resp.State.RemoveResource(ctx)
return return
} }

View file

@ -1,13 +1,19 @@
package utils package utils
import ( import (
"context"
"errors"
"fmt" "fmt"
"regexp" "regexp"
"strings" "strings"
"github.com/hashicorp/terraform-plugin-framework/diag"
"github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-plugin-framework/types"
"github.com/hashicorp/terraform-plugin-framework/types/basetypes" "github.com/hashicorp/terraform-plugin-framework/types/basetypes"
"github.com/hashicorp/terraform-plugin-log/tflog"
"github.com/stackitcloud/stackit-sdk-go/core/oapierror"
"github.com/stackitcloud/stackit-sdk-go/core/utils" "github.com/stackitcloud/stackit-sdk-go/core/utils"
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/core"
) )
const ( const (
@ -114,3 +120,27 @@ type value interface {
func IsUndefined(val value) bool { func IsUndefined(val value) bool {
return val.IsUnknown() || val.IsNull() return val.IsUnknown() || val.IsNull()
} }
// LogError logs errors. In descriptions different messages for http status codes can be passed. When no one matches the defaultDescription will be used
func LogError(ctx context.Context, inputDiags *diag.Diagnostics, err error, summary, defaultDescription string, descriptions map[int]string) {
if err == nil {
return
}
tflog.Error(ctx, fmt.Sprintf("%s. Err: %v", summary, err))
var oapiErr *oapierror.GenericOpenAPIError
ok := errors.As(err, &oapiErr)
if !ok {
core.LogAndAddError(ctx, inputDiags, summary, fmt.Sprintf("Calling API: %v", err))
return
}
var description string
if len(descriptions) != 0 {
description, ok = descriptions[oapiErr.StatusCode]
}
if !ok || description == "" {
description = defaultDescription
}
core.LogAndAddError(ctx, inputDiags, summary, description)
}

View file

@ -13,9 +13,6 @@ import (
"github.com/hashicorp/terraform-plugin-framework/schema/validator" "github.com/hashicorp/terraform-plugin-framework/schema/validator"
"github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-plugin-framework/types"
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/features" "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/features"
argusCredential "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/services/argus/credential"
argusInstance "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/services/argus/instance"
argusScrapeConfig "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/services/argus/scrapeconfig"
roleassignments "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/services/authorization/roleassignments" roleassignments "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/services/authorization/roleassignments"
dnsRecordSet "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/services/dns/recordset" dnsRecordSet "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/services/dns/recordset"
dnsZone "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/services/dns/zone" dnsZone "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/services/dns/zone"
@ -465,8 +462,6 @@ func (p *Provider) Configure(ctx context.Context, req provider.ConfigureRequest,
// DataSources defines the data sources implemented in the provider. // DataSources defines the data sources implemented in the provider.
func (p *Provider) DataSources(_ context.Context) []func() datasource.DataSource { func (p *Provider) DataSources(_ context.Context) []func() datasource.DataSource {
return []func() datasource.DataSource{ return []func() datasource.DataSource{
argusInstance.NewInstanceDataSource,
argusScrapeConfig.NewScrapeConfigDataSource,
dnsZone.NewZoneDataSource, dnsZone.NewZoneDataSource,
dnsRecordSet.NewRecordSetDataSource, dnsRecordSet.NewRecordSetDataSource,
iaasAffinityGroup.NewAffinityGroupDatasource, iaasAffinityGroup.NewAffinityGroupDatasource,
@ -520,9 +515,6 @@ func (p *Provider) DataSources(_ context.Context) []func() datasource.DataSource
// Resources defines the resources implemented in the provider. // Resources defines the resources implemented in the provider.
func (p *Provider) Resources(_ context.Context) []func() resource.Resource { func (p *Provider) Resources(_ context.Context) []func() resource.Resource {
resources := []func() resource.Resource{ resources := []func() resource.Resource{
argusCredential.NewCredentialResource,
argusInstance.NewInstanceResource,
argusScrapeConfig.NewScrapeConfigResource,
dnsZone.NewZoneResource, dnsZone.NewZoneResource,
dnsRecordSet.NewRecordSetResource, dnsRecordSet.NewRecordSetResource,
iaasAffinityGroup.NewAffinityGroupResource, iaasAffinityGroup.NewAffinityGroupResource,