Skip to content

Commit 90fe355

Browse files
feat(logs) onboard logs service (#1096)
* feat(logs) onboard logs service - add resource with examples - add data source with examples - add acceptance tests * fix(logs) generate docs * fix(logs) update logs dependency to version with waiters * fix(logs) linting errors * fix(logs) review issues - rename git to logs in example - add NoSeparator validator for instance-/project-id - log responses and instance_ids - rm redundant struct field docs - mention possible status values in description - test ConfigureClient - use ElementsAs * fix(logs) generate docs * fix(logs) correctly set region in instance data source * fix(logs) add examples to docs * fix(logs) pass core.Datasource to datasoure MarkdownDescription * fix(logs) regenerate docs
1 parent 44312a8 commit 90fe355

File tree

18 files changed

+1642
-0
lines changed

18 files changed

+1642
-0
lines changed

docs/data-sources/logs_instance.md

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
---
2+
# generated by https://github.com/hashicorp/terraform-plugin-docs
3+
page_title: "stackit_logs_instance Data Source - stackit"
4+
subcategory: ""
5+
description: |-
6+
Logs instance data source schema.
7+
~> This datasource is in beta and may be subject to breaking changes in the future. Use with caution. See our guide https://registry.terraform.io/providers/stackitcloud/stackit/latest/docs/guides/opting_into_beta_resources for how to opt-in to use beta resources.
8+
---
9+
10+
# stackit_logs_instance (Data Source)
11+
12+
Logs instance data source schema.
13+
14+
~> This datasource is in beta and may be subject to breaking changes in the future. Use with caution. See our [guide](https://registry.terraform.io/providers/stackitcloud/stackit/latest/docs/guides/opting_into_beta_resources) for how to opt-in to use beta resources.
15+
16+
## Example Usage
17+
18+
```terraform
19+
data "stackit_logs_instance" "logs" {
20+
project_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
21+
region = "eu01"
22+
instance_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
23+
}
24+
```
25+
26+
<!-- schema generated by tfplugindocs -->
27+
## Schema
28+
29+
### Required
30+
31+
- `instance_id` (String) The Logs instance ID
32+
- `project_id` (String) STACKIT project ID associated with the Logs instance
33+
34+
### Optional
35+
36+
- `region` (String) STACKIT region name the resource is located in. If not defined, the provider region is used.
37+
38+
### Read-Only
39+
40+
- `acl` (List of String) The access control list entries for the Logs instance
41+
- `created` (String) The date and time the creation of the Logs instance was initiated
42+
- `datasource_url` (String) Logs instance datasource URL, can be used in Grafana as datasource URL
43+
- `description` (String) The description of the Logs instance
44+
- `display_name` (String) The displayed name of the Logs instance
45+
- `id` (String) Terraform's internal resource identifier. It is structured as "`project_id`,`region`,`instance_id`".
46+
- `ingest_otlp_url` (String) The Logs instance's ingest logs via OTLP URL
47+
- `ingest_url` (String) The logs instance's ingest logs URL
48+
- `query_range_url` (String) The Logs instance's query range URL
49+
- `query_url` (String) The Logs instance's query URL
50+
- `retention_days` (Number) The log retention time in days
51+
- `status` (String) The status of the Logs instance, possible values: Possible values are: `active`, `deleting`, `reconciling`.

docs/index.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,7 @@ Note: AWS specific checks must be skipped as they do not work on STACKIT. For de
166166
- `kms_custom_endpoint` (String) Custom endpoint for the KMS service
167167
- `loadbalancer_custom_endpoint` (String) Custom endpoint for the Load Balancer service
168168
- `logme_custom_endpoint` (String) Custom endpoint for the LogMe service
169+
- `logs_custom_endpoint` (String) Custom endpoint for the Logs service
169170
- `mariadb_custom_endpoint` (String) Custom endpoint for the MariaDB service
170171
- `modelserving_custom_endpoint` (String) Custom endpoint for the AI Model Serving service
171172
- `mongodbflex_custom_endpoint` (String) Custom endpoint for the MongoDB Flex service

docs/resources/logs_instance.md

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
---
2+
# generated by https://github.com/hashicorp/terraform-plugin-docs
3+
page_title: "stackit_logs_instance Resource - stackit"
4+
subcategory: ""
5+
description: |-
6+
Logs instance resource schema.
7+
~> This resource is in beta and may be subject to breaking changes in the future. Use with caution. See our guide https://registry.terraform.io/providers/stackitcloud/stackit/latest/docs/guides/opting_into_beta_resources for how to opt-in to use beta resources.
8+
---
9+
10+
# stackit_logs_instance (Resource)
11+
12+
Logs instance resource schema.
13+
14+
~> This resource is in beta and may be subject to breaking changes in the future. Use with caution. See our [guide](https://registry.terraform.io/providers/stackitcloud/stackit/latest/docs/guides/opting_into_beta_resources) for how to opt-in to use beta resources.
15+
16+
## Example Usage
17+
18+
```terraform
19+
resource "stackit_logs_instance" "logs" {
20+
project_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
21+
region = "eu01"
22+
display_name = "logs-instance-example"
23+
retention_days = 30
24+
}
25+
26+
resource "stackit_logs_instance" "logs2" {
27+
project_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
28+
region = "eu01"
29+
display_name = "logs-instance-example"
30+
retention_days = 30
31+
acl = [
32+
"0.0.0.0/0"
33+
]
34+
description = "Example description"
35+
}
36+
37+
# Only use the import statement, if you want to import an existing logs instance
38+
import {
39+
to = stackit_logs_instance.import-example
40+
id = "${var.project_id},${var.region},${var.logs_instance_id}"
41+
}
42+
```
43+
44+
<!-- schema generated by tfplugindocs -->
45+
## Schema
46+
47+
### Required
48+
49+
- `display_name` (String) The displayed name of the Logs instance
50+
- `project_id` (String) STACKIT project ID associated with the Logs instance
51+
- `retention_days` (Number) The log retention time in days
52+
53+
### Optional
54+
55+
- `acl` (List of String) The access control list entries for the Logs instance
56+
- `description` (String) The description of the Logs instance
57+
- `region` (String) STACKIT region name the resource is located in. If not defined, the provider region is used.
58+
59+
### Read-Only
60+
61+
- `created` (String) The date and time the creation of the Logs instance was initiated
62+
- `datasource_url` (String) Logs instance datasource URL, can be used in Grafana as datasource URL
63+
- `id` (String) Terraform's internal resource identifier. It is structured as "`project_id`,`region`,`instance_id`".
64+
- `ingest_otlp_url` (String) The Logs instance's ingest logs via OTLP URL
65+
- `ingest_url` (String) The logs instance's ingest logs URL
66+
- `instance_id` (String) The Logs instance ID
67+
- `query_range_url` (String) The Logs instance's query range URL
68+
- `query_url` (String) The Logs instance's query URL
69+
- `status` (String) The status of the Logs instance, possible values: Possible values are: `active`, `deleting`, `reconciling`.
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
data "stackit_logs_instance" "logs" {
2+
project_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
3+
region = "eu01"
4+
instance_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
5+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
resource "stackit_logs_instance" "logs" {
2+
project_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
3+
region = "eu01"
4+
display_name = "logs-instance-example"
5+
retention_days = 30
6+
}
7+
8+
resource "stackit_logs_instance" "logs2" {
9+
project_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
10+
region = "eu01"
11+
display_name = "logs-instance-example"
12+
retention_days = 30
13+
acl = [
14+
"0.0.0.0/0"
15+
]
16+
description = "Example description"
17+
}
18+
19+
# Only use the import statement, if you want to import an existing logs instance
20+
import {
21+
to = stackit_logs_instance.import-example
22+
id = "${var.project_id},${var.region},${var.logs_instance_id}"
23+
}

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ require (
2121
github.com/stackitcloud/stackit-sdk-go/services/kms v1.2.0
2222
github.com/stackitcloud/stackit-sdk-go/services/loadbalancer v1.6.2
2323
github.com/stackitcloud/stackit-sdk-go/services/logme v0.25.3
24+
github.com/stackitcloud/stackit-sdk-go/services/logs v0.3.0
2425
github.com/stackitcloud/stackit-sdk-go/services/mariadb v0.25.3
2526
github.com/stackitcloud/stackit-sdk-go/services/modelserving v0.6.2
2627
github.com/stackitcloud/stackit-sdk-go/services/mongodbflex v1.5.5

go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,8 @@ github.com/stackitcloud/stackit-sdk-go/services/loadbalancer v1.6.2 h1:DwwRMzvnK
171171
github.com/stackitcloud/stackit-sdk-go/services/loadbalancer v1.6.2/go.mod h1:dYmNdSNDKUG+E0SwuFWu+c8CuMBF/l6w1bdzAHxQao0=
172172
github.com/stackitcloud/stackit-sdk-go/services/logme v0.25.3 h1:fUQLWs2WsXFh+FtFDYOm1kv/gJrGBZLjhVOXJOuYfFY=
173173
github.com/stackitcloud/stackit-sdk-go/services/logme v0.25.3/go.mod h1:305j9bvzJ+3c4csOw4SUfLSSxRbkpL0osbvqMI89FeM=
174+
github.com/stackitcloud/stackit-sdk-go/services/logs v0.3.0 h1:N1gerABK2vH7/PBkxZeaWYJ7dz3rjeCHuto+FAuGx3w=
175+
github.com/stackitcloud/stackit-sdk-go/services/logs v0.3.0/go.mod h1:m4IjH1/RtJOF072kjAB0E/ejoIc++myrKmIahphfO6Q=
174176
github.com/stackitcloud/stackit-sdk-go/services/mariadb v0.25.3 h1:Y5Ct3Zi5UcIOwjKMWpKl0nrqiq7psTf4NJv0IKgwTkc=
175177
github.com/stackitcloud/stackit-sdk-go/services/mariadb v0.25.3/go.mod h1:TMl5WcpjzUiAlLWaxMKbu9ysDzFziSPgg4xLxj9jjfY=
176178
github.com/stackitcloud/stackit-sdk-go/services/modelserving v0.6.2 h1:RKRKwSpU8spBERYNlUn9BcTL3dbTLeJM1xL2H7NexnI=

stackit/internal/core/core.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ type ProviderData struct {
5252
KMSCustomEndpoint string
5353
LoadBalancerCustomEndpoint string
5454
LogMeCustomEndpoint string
55+
LogsCustomEndpoint string
5556
MariaDBCustomEndpoint string
5657
MongoDBFlexCustomEndpoint string
5758
ModelServingCustomEndpoint string
Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,180 @@
1+
package instance
2+
3+
import (
4+
"context"
5+
"errors"
6+
"fmt"
7+
"net/http"
8+
9+
"github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
10+
"github.com/hashicorp/terraform-plugin-framework/datasource"
11+
"github.com/hashicorp/terraform-plugin-framework/datasource/schema"
12+
"github.com/hashicorp/terraform-plugin-framework/schema/validator"
13+
"github.com/hashicorp/terraform-plugin-framework/types"
14+
"github.com/hashicorp/terraform-plugin-log/tflog"
15+
"github.com/stackitcloud/stackit-sdk-go/core/oapierror"
16+
"github.com/stackitcloud/stackit-sdk-go/services/logs"
17+
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/conversion"
18+
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/core"
19+
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/features"
20+
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/services/logs/utils"
21+
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/validate"
22+
)
23+
24+
var (
25+
_ datasource.DataSource = &logsInstanceDataSource{}
26+
)
27+
28+
func NewLogsInstanceDataSource() datasource.DataSource {
29+
return &logsInstanceDataSource{}
30+
}
31+
32+
type logsInstanceDataSource struct {
33+
client *logs.APIClient
34+
providerData core.ProviderData
35+
}
36+
37+
func (d *logsInstanceDataSource) Metadata(_ context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) {
38+
resp.TypeName = req.ProviderTypeName + "_logs_instance"
39+
}
40+
41+
func (d *logsInstanceDataSource) Configure(ctx context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) {
42+
providerData, ok := conversion.ParseProviderData(ctx, req.ProviderData, &resp.Diagnostics)
43+
if !ok {
44+
return
45+
}
46+
d.providerData = providerData
47+
48+
apiClient := utils.ConfigureClient(ctx, &providerData, &resp.Diagnostics)
49+
if resp.Diagnostics.HasError() {
50+
return
51+
}
52+
d.client = apiClient
53+
tflog.Info(ctx, "Logs client configured")
54+
}
55+
56+
func (d *logsInstanceDataSource) Schema(_ context.Context, _ datasource.SchemaRequest, resp *datasource.SchemaResponse) {
57+
resp.Schema = schema.Schema{
58+
MarkdownDescription: features.AddBetaDescription("Logs instance data source schema.", core.Datasource),
59+
Description: fmt.Sprintf("Logs instance resource schema. %s", core.DatasourceRegionFallbackDocstring),
60+
Attributes: map[string]schema.Attribute{
61+
"id": schema.StringAttribute{
62+
Description: schemaDescriptions["id"],
63+
Computed: true,
64+
},
65+
"instance_id": schema.StringAttribute{
66+
Description: schemaDescriptions["instance_id"],
67+
Required: true,
68+
Validators: []validator.String{
69+
validate.UUID(),
70+
validate.NoSeparator(),
71+
},
72+
},
73+
"region": schema.StringAttribute{
74+
Description: schemaDescriptions["region"],
75+
// the region cannot be found, so it has to be passed
76+
Optional: true,
77+
},
78+
"project_id": schema.StringAttribute{
79+
Description: schemaDescriptions["project_id"],
80+
Required: true,
81+
Validators: []validator.String{
82+
validate.UUID(),
83+
validate.NoSeparator(),
84+
},
85+
},
86+
"acl": schema.ListAttribute{
87+
Description: schemaDescriptions["acl"],
88+
ElementType: types.StringType,
89+
Computed: true,
90+
},
91+
"created": schema.StringAttribute{
92+
Description: schemaDescriptions["created"],
93+
Computed: true,
94+
},
95+
"datasource_url": schema.StringAttribute{
96+
Description: schemaDescriptions["datasource_url"],
97+
Computed: true,
98+
},
99+
"description": schema.StringAttribute{
100+
Description: schemaDescriptions["description"],
101+
Computed: true,
102+
},
103+
"display_name": schema.StringAttribute{
104+
Description: schemaDescriptions["display_name"],
105+
Computed: true,
106+
Validators: []validator.String{stringvalidator.LengthAtLeast(1)},
107+
},
108+
"ingest_otlp_url": schema.StringAttribute{
109+
Description: schemaDescriptions["ingest_otlp_url"],
110+
Computed: true,
111+
},
112+
"ingest_url": schema.StringAttribute{
113+
Description: schemaDescriptions["ingest_url"],
114+
Computed: true,
115+
},
116+
"query_range_url": schema.StringAttribute{
117+
Description: schemaDescriptions["query_range_url"],
118+
Computed: true,
119+
},
120+
"query_url": schema.StringAttribute{
121+
Description: schemaDescriptions["query_url"],
122+
Computed: true,
123+
},
124+
"retention_days": schema.Int64Attribute{
125+
Description: schemaDescriptions["retention_days"],
126+
Computed: true,
127+
},
128+
"status": schema.StringAttribute{
129+
Description: schemaDescriptions["status"],
130+
Computed: true,
131+
},
132+
},
133+
}
134+
}
135+
136+
func (d *logsInstanceDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { // nolint:gocritic // function signature required by Terraform
137+
var model Model
138+
diags := req.Config.Get(ctx, &model)
139+
resp.Diagnostics.Append(diags...)
140+
if resp.Diagnostics.HasError() {
141+
return
142+
}
143+
144+
ctx = core.InitProviderContext(ctx)
145+
146+
projectID := model.ProjectID.ValueString()
147+
region := d.providerData.GetRegionWithOverride(model.Region)
148+
instanceID := model.InstanceID.ValueString()
149+
150+
ctx = tflog.SetField(ctx, "project_id", projectID)
151+
ctx = tflog.SetField(ctx, "region", region)
152+
ctx = tflog.SetField(ctx, "instance_id", instanceID)
153+
154+
instanceResponse, err := d.client.GetLogsInstance(ctx, projectID, region, instanceID).Execute()
155+
if err != nil {
156+
var oapiErr *oapierror.GenericOpenAPIError
157+
ok := errors.As(err, &oapiErr)
158+
if ok && oapiErr.StatusCode == http.StatusNotFound {
159+
resp.State.RemoveResource(ctx)
160+
return
161+
}
162+
core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading logs instance", fmt.Sprintf("Calling API: %v", err))
163+
return
164+
}
165+
ctx = core.LogResponse(ctx)
166+
167+
err = mapFields(ctx, instanceResponse, &model)
168+
if err != nil {
169+
core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading logs instance", fmt.Sprintf("Processing response: %v", err))
170+
return
171+
}
172+
diags = resp.State.Set(ctx, model)
173+
resp.Diagnostics.Append(diags...)
174+
if resp.Diagnostics.HasError() {
175+
return
176+
}
177+
tflog.Info(ctx, "Logs Instance read", map[string]interface{}{
178+
"instance_id": instanceID,
179+
})
180+
}

0 commit comments

Comments
 (0)